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 方法中如何使用符号来识别参数的主要内容,如果未能解决你的问题,请参考以下文章

方法如何在 Ruby 中使用哈希参数?

ruby 上使用 lbs 或 ' 和 " 符号输入时如何验证表单字段中的身高和体重

如何理解 Ruby 中的符号

如何理解 Ruby 中的符号

如何在Ruby中使用来自哈希的查询参数构造URI

ruby:对符号数组进行排序