ruby 方法中如何使用符号来识别参数
Posted
技术标签:
【中文标题】ruby 方法中如何使用符号来识别参数【英文标题】:How are symbols used to identify arguments in ruby methods 【发布时间】: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("布鲁斯", "狄更斯")
【参考方案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
是用作哈希键的符号——任何类型都可以用作哈希键,但符号是一种常见的选择,因为它们是不可变的值。
【讨论】:
而且,比不可变更重要的是,它们更具交流性,因为它们专门充当某事物的名称或标签。以上是关于ruby 方法中如何使用符号来识别参数的主要内容,如果未能解决你的问题,请参考以下文章