从ruby内部进行施工质量分配

可能重复:
在ruby中创建惯用对象

有时,在构造上为实例变量分配许多构造的参数是有用的。 除了明显的方法:

def initialize(arg1, arg2, arg3) @arg1, @arg2, @arg3 = arg1, arg2, arg3 end 

是否有更简洁的习惯用于实现相同的结果? 像scala中发现的东西,例如:

 class FancyGreeter(greeting: String) { def greet() = println(greeting) } 

在这种情况下,对象FancyGreeter有一个默认构造函数,为它传递的参数提供赋值。

在Ruby 1.8中,块参数和方法参数具有不同的语义:方法参数具有绑定语义 ,块参数具有赋值语义

这意味着当您调用方法时,方法参数将绑定到您传入的值。当您调用块时,值将被赋值给参数。

所以,你可以创建一些非常疯狂的块,这似乎没有做任何事情:

 lambda {|@a|}.call(42) 

块体是空的,但由于参数赋值语义,实例变量@a将被赋值42 。 它的工作更加疯狂:

 lambda {|foo.bar|}.call(42) 

是的, attr_writer方法也可以。 或者怎么样

 foo = {} lambda {|foo[:bar]|}.call(42) p foo # => {:bar => 42} 

是的,那些。

由于您可以使用块定义方法,因此您可以这样做:

 class FancyGreeter define_method(:initialize) {|@greeting|} def greet; puts @greeting end end 

甚至

 class FancyGreeter attr_accessor :greeting define_method(:initialize) {|self.greeting|} def greet; puts greeting end end 

但是,我不建议这样做有两个原因:

  • 没有多少Rubyist知道这一点,对那些必须在你之后维护代码的人表示友好。
  • 在Ruby 1.9及更高版本中,块参数语义已经消失,块也使用方法参数语义,因此这不再起作用。

我想你可以做….

 def initialize *e @a, @b, @c = e end 

我不知道“更好”,但有不同程度的“聪明”:

 def initialize args={} args.each do |key, value| instance_variable_set "@#{key}", value end end 

但是,当你编程时,“聪明”通常是危险的:-)


编辑:鉴于编辑过的问题,我将添加:

 Class PickMe def initialize say="what?" @say = say end end 

仅仅因为我不知道你是否知道默认选项。 否则,请考虑自我记录代码的价值。 干净利落的“初始化”方法是无价的。

是Andy Hunt或Dave Thomas提出Ruby应该能够处理这种语法来从构造函数参数初始化成员变量:

  def initialize(@a, @b, @c) ... end 

马茨不接受他们的建议; 我不记得为什么。