问题
Possible Duplicate:
Idiomatic object creation in ruby
Sometimes it's useful to assign numerous of a constructed arguments to instance variables on construction. Other than the obvious method:
def initialize(arg1, arg2, arg3)
@arg1, @arg2, @arg3 = arg1, arg2, arg3
end
Is there a more concise idiom for achieving the same result? Something like that found in scala for instance:
class FancyGreeter(greeting: String) {
def greet() = println(greeting)
}
Where in this case the object FancyGreeter has a default constructor that provides assignment for it's passed arguments.
回答1:
In Ruby 1.8, block arguments and method arguments have different semantics: method arguments have binding semantics, block arguments have assignment semantics.
What that means is that when you call a method, the method arguments get bound to the values that you pass in. When you call a block, the values get assigned to the arguments.
So, you can create some pretty crazy looking blocks that way, that seemingly don't do anything:
lambda {|@a|}.call(42)
The block body is empty, but because of the argument assignment semantics, the instance variable @a
will be assigned the value 42
. It works even crazier:
lambda {|foo.bar|}.call(42)
Yes, attr_writer
methods work too. Or what about
foo = {}
lambda {|foo[:bar]|}.call(42)
p foo # => {:bar => 42}
Yup, those too.
And since you can define methods using blocks, you can do this:
class FancyGreeter
define_method(:initialize) {|@greeting|}
def greet; puts @greeting end
end
or even
class FancyGreeter
attr_accessor :greeting
define_method(:initialize) {|self.greeting|}
def greet; puts greeting end
end
However, I wouldn't recommend this for two reasons:
- Not many Rubyists know this, be kind to the people who have to maintain the code after you.
- In Ruby 1.9 and onwards, block argument semantics are gone, blocks also use method argument semantics, therefore this does no longer work.
回答2:
I suppose you could do....
def initialize *e
@a, @b, @c = e
end
回答3:
I don't know about "better" but there are varying levels of 'clever':
def initialize args={}
args.each do |key, value|
instance_variable_set "@#{key}", value
end
end
But "clever" is usually dangerous when you program :-)
Edit: Given the edited question, I'll add this:
Class PickMe
def initialize say="what?"
@say = say
end
end
Just because I don't know if you're aware of default options. Otherwise, think of the value of self-documenting code. A cleanly-written 'initialize' method is priceless.
回答4:
It was either Andy Hunt or Dave Thomas who proposed that Ruby should be able to handle this syntax for initializing member variables from constructor arguments:
def initialize(@a, @b, @c)
...
end
Matz did not accept their proposal; I don't remember why.
来源:https://stackoverflow.com/questions/2268216/mass-assignment-on-construction-from-within-ruby