【发布时间】:2011-07-21 10:41:42
【问题描述】:
我对 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 中的结构将其成员存储为符号,但在 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 风格。
【问题讨论】:
-
你的代码看起来不错,真的。
-
我一直在寻找同样的东西 - 是否有一个标准的 gem 可以做到这一点,以及指定哪些参数是必需的?
-
github.com/chemica/solid-struct 执行此操作,但不强制执行必需的参数。
标签: ruby struct named-parameters