【问题标题】:How are symbols used to identify arguments in ruby methodsruby 方法中如何使用符号来识别参数
【发布时间】:2011-12-22 17:25:11
【问题描述】:

我正在学习 rails 并回到 ruby​​ 以了解 rails 中的方法(以及 ruby​​ 真正起作用)。当我看到这样的方法调用时:

validates :first_name, :presence => true

我很困惑。您如何在 ruby​​ 中编写接受符号或哈希的方法。 validates 方法的源代码也很混乱。有人可以为我简化在 ruby​​ 类和实例方法中使用符号作为参数的主题吗?

更新:

好一个@Dave!但我尝试的是这样的:

def full_name (:first_name, :last_name)
  @first_name = :first_name
  @last_name = :last_name
  p "#{@first_name} #{last_name}"
end

full_name("Breta", "Von Sustern")

这显然会引发错误。我试图理解:如果符号与任何其他值一样,为什么将这样的符号作为参数传递是错误的?

【问题讨论】:

  • 符号和散列值与其他任何值一样 - 传递符号或散列值与其他任何东西没有什么不同。具体是什么让您感到困惑?
  • 令我困惑的是,我从未见过在 ruby​​ 方法中将哈希用作值的示例。所以我无法想象你在说什么。
  • pass符号,参数名还是那个--参数名,不能有:开头的字符。
  • 啊!所以我愚蠢的问题的答案是,我不能在构造方法时将符号作为参数传递,但是当我调用它们时我可以。对吗?
  • 正确。当你定义一个方法时,你没有传递任何东西。您正在命名调用此方法时将传递的参数。因此,在您的示例中,它只是: def full_name(first_name, last_name) 但这是一个不好的示例,因为您不会将名字和姓氏作为符号传递,而是将它们作为字符串传递,例如person.full_name("布鲁斯", "狄更斯")

标签: ruby-on-rails ruby symbols hash


【解决方案1】:

符号和散列值与任何其他值一样,可以像任何其他值类型一样传递。

回想一下,ActiveRecord 模型接受散列作为参数;它最终与此相似(不是那么简单,但最终是相同的想法):

class User
  attr_accessor :fname, :lname

  def initialize(args)
    @fname = args[:fname] if args[:fname]
    @lname = args[:lname] if args[:lname]
  end
end

u = User.new(:fname => 'Joe', :lname => 'Hacker')

这利用了不必将散列放在花括号 {} 中的优势,除非您需要消除参数的歧义(当您跳过括号时也会出现块解析问题)。

同样:

class TestItOut
  attr_accessor :field_name, :validations

  def initialize(field_name, validations)
    @field_name = field_name
    @validations = validations
  end

  def show_validations
    puts "Validating field '#{field_name}' with:"
    validations.each do |type, args|
      puts "  validator '#{type}' with args '#{args}'"
    end
  end
end

t = TestItOut.new(:name, presence: true, length: { min: 2, max: 10 })
t.show_validations

这个输出:

Validating field 'name' with:
  validator 'presence' with args 'true'
  validator 'length' with args '{min: 2, max: 10}'

您可以从那里开始了解类似的工作方式。

【讨论】:

  • 另外,在获取散列中的参数时,考虑使用fetch 方法提供默认值。
  • 初始化定义中的评估不是必须是*validations吗?
  • @RyanDsouza 我不确定你的意思;我有错字吗?
【解决方案2】:

我想我应该为 Ruby 2+ 添加一个更新,因为这是我找到的“符号作为参数”的第一个结果。

从 Ruby 2.0.0 开始,您还可以在定义方法时使用符号。当调用该方法时,这些符号的行为几乎与其他语言中的命名可选参数相同。请参见下面的示例:

def variable_symbol_method(arg, arg_two: "two", arg_three: "three")
  [arg, arg_two, arg_three]
end

result = variable_symbol_method :custom_symbol, arg_three: "Modified symbol arg"

# result is now equal to:
[:custom_symbol, "two", "Modified symbol arg"]

如示例中所示,我们在调用方法时省略了arg_two:,在方法体中我们仍然可以将其作为变量arg_two 访问。还要注意变量arg_three 确实被函数调用改变了。

【讨论】:

    【解决方案3】:

    我认为所有回复都错过了问题的重点;有人问过这个问题——我猜——不清楚符号是什么?

    作为 Ruby 的新手,我也有类似的困惑,对我来说,像下面这样的答案会更有意义

    方法参数是由传入值填充的局部变量。

    您不能将符号用作参数本身,因为您无法更改符号的值。

    【讨论】:

    • 我不确定您所说的“您不能将符号本身用作参数”是什么意思,因为您可以...foo(:bar) 是一个完全合法的函数调用。可能我理解错了?
    • 我认为@sevgun 的意思是“您不能单独使用符号作为参数”,其中使用定义“参数是指方法声明中的变量列表. 参数是调用方法时传入的实际值。"
    【解决方案4】:

    符号不限于散列。它们是标识符,没有字符串的额外存储空间。这只是一种表达“这是……”的方式

    validates 调用的一个可能的函数定义可能是(为了简化,我不知道它到底是什么):

    def validates(column, options)
       puts column.to_s
       if options[:presence]
         puts "Found a presence option"
       end
     end
    

    注意第一个符号是如何单独作为参数的,其余的是散列。

    【讨论】:

    • 它们仍然被存储,只是每个唯一标签只存储一次,就像一个实习字符串。 OTOH,他们也没有资格获得 GC(也许他们在 1.9 中),所以他们在应用程序的生命周期内一直存在。
    • 符号在 1.9 中也没有被 GC。
    • Ruby 2.2 现在有符号 GC
    【解决方案5】:

    在 Ruby 中,如果您在参数列表末尾调用带有一组 name => value 对的方法,它们会自动包装在 Hash 中并作为最后一个参数传递给您的方法:

    def foo(kwargs)
      p kwargs
    end
    
    >> foo(:abc=>"def", 123=>456)
    {:abc=>"def", 123=>456}
    
    >> foo("cabbage")
    "cabbage"
    
    >> foo(:fluff)
    :fluff
    

    您如何编写方法并没有什么“特别”之处,就是您如何调用它。将常规 Hash 对象作为 kwargs 参数传递是完全合法的。此语法快捷方式用于在 API 中实现命名参数

    Ruby 符号和其他符号一样只是一个值,因此在您的示例中,:first_name 只是一个常规位置参数。 :presence 是用作哈希键的符号——任何类型都可以用作哈希键,但符号是一种常见的选择,因为它们是不可变的值。

    【讨论】:

    • 而且,比不可变更重要的是,它们更具交流性,因为它们专门充当某事物的名称或标签。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多