我对 Ruby 很陌生,如果这是一个明显的问题,我深表歉意。
我想在实例化 Struct 时使用命名参数,即能够指定 Struct 中的哪些项获取哪些值,并将其余项默认为 nil。
例如我想做:
Movie = Struct.new :title, :length, :rating
m = Movie.new :title => 'Some Movie', :rating => 'R'
这行不通。
所以我想出了以下内容:
class MyStruct < Struct
# Override the initialize to handle hashes of named parameters
def initialize *args
if (args.length == 1 and args.first.instance_of? Hash) then
args.first.each_pair do |k, v|
if members.include? k then
self[k] = v
end
end
else
super *args
end
end
end
Movie = MyStruct.new :title, :length, :rating
m = Movie.new :title => 'Some Movie', :rating => 'R'
这似乎工作得很好,但我不确定是否有更好的方法可以做到这一点,或者我是否正在做一些非常疯狂的事情。如果有人可以验证/撕开这种方法,我将不胜感激。
更新
我最初在 1.9.2 中运行它,它工作正常;但是在其他版本的 Ruby 中尝试过(谢谢 rvm),它的工作/不工作如下:
- 1.8.7:不工作
- 1.9.1:工作
- 1.9.2:工作
- JRuby(设置为 1.9.2 运行):不工作
JRuby 对我来说是个问题,因为我想让它与它兼容以用于部署目的。
另一个更新
在这个不断增加的杂乱无章的问题中,我尝试了各种版本的 Ruby,发现 1.9.x 中的 Struct 将其成员存储为符号,但在 1.8.7 和 JRuby 中,它们存储为字符串,因此我将代码更新为如下(考虑已经给出的建议):
class MyStruct < Struct
# Override the initialize to handle hashes of named parameters
def initialize *args
return super unless (args.length == 1 and args.first.instance_of? Hash)
args.first.each_pair do |k, v|
self[k] = v if members.map {|x| x.intern}.include? k
end
end
end
Movie = MyStruct.new :title, :length, :rating
m = Movie.new :title => 'Some Movie', :rating => 'R'
现在这似乎适用于我尝试过的所有 Ruby 风格。