Ruby Structs 中的命名参数 [英] Named Parameters in Ruby Structs

查看:35
本文介绍了Ruby Structs 中的命名参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对 Ruby 还很陌生,如果这是一个明显的问题,我深表歉意.

I'm pretty new to Ruby so apologies if this is an obvious question.

我想在实例化 Struct 时使用命名参数,即能够指定 Struct 中的哪些项获取哪些值,其余部分默认为零.

I'd like to use named parameters when instantiating a Struct, i.e. be able to specify which items in the Struct get what values, and default the rest to nil.

例如我想做:

Movie = Struct.new :title, :length, :rating
m = Movie.new :title => 'Some Movie', :rating => 'R'

这不起作用.

所以我想出了以下内容:

So I came up with the following:

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'

这似乎工作得很好,但我不确定是否有更好的方法来做到这一点,或者我是否正在做一些非常疯狂的事情.如果有人可以验证/分解这种方法,我将不胜感激.

This seems to work just fine, but I'm not sure if there's a better way of doing this, or if I'm doing something pretty insane. If anyone can validate/rip apart this approach, I'd be most grateful.

更新

我最初是在 1.9.2 中运行的,它运行良好;但是在其他版本的 Ruby 中尝试过(谢谢 rvm),它的工作/不工作如下:

I ran this initially in 1.9.2 and it works fine; however having tried it in other versions of Ruby (thank you rvm), it works/doesn't work as follows:

  • 1.8.7:不工作
  • 1.9.1:工作
  • 1.9.2:工作
  • JRuby(设置为 1.9.2):不工作

JRuby 对我来说是个问题,因为为了部署目的,我希望它与它兼容.

JRuby is a problem for me, as I'd like to keep it compatible with that for deployment purposes.

另一个更新

在这个不断增加的漫无边际的问题中,我尝试了 Ruby 的各种版本,发现 1.9.x 中的 Structs 将其成员存储为符号,但在 1.8.7 和 JRuby 中,它们存储为字符串,因此我更新了代码如下(接受已经提出的建议):

In this ever-increasing rambling question, I experimented with the various versions of Ruby and discovered that Structs in 1.9.x store their members as symbols, but in 1.8.7 and JRuby, they are stored as strings, so I updated the code to be the following (taking in the suggestions already kindly given):

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 风格.

This now appears to work for all the flavours of Ruby that I've tried.

推荐答案

综合现有答案为 Ruby 2.0+ 提供了一个更简单的选项:

Synthesizing the existing answers reveals a much simpler option for Ruby 2.0+:

class KeywordStruct < Struct
  def initialize(**kwargs)
    super(*members.map{|k| kwargs[k] })
  end
end

用法与现有的 Struct 相同,其中任何未给出的参数将默认为 nil:

Usage is identical to the existing Struct, where any argument not given will default to nil:

Pet = KeywordStruct.new(:animal, :name)
Pet.new(animal: "Horse", name: "Bucephalus") # => #<struct Pet animal="Horse", name="Bucephalus">  
Pet.new(name: "Bob") # => #<struct Pet animal=nil, name="Bob"> 

如果你想要像 Ruby 2.1+ 的必需 kwargs 这样的参数,这是一个很小的变化:

If you want to require the arguments like Ruby 2.1+'s required kwargs, it's a very small change:

class RequiredKeywordStruct < Struct
  def initialize(**kwargs)
    super(*members.map{|k| kwargs.fetch(k) })
  end
end

此时,覆盖 initialize 以提供某些 kwargs 默认值也是可行的:

At that point, overriding initialize to give certain kwargs default values is also doable:

Pet = RequiredKeywordStruct.new(:animal, :name) do
  def initialize(animal: "Cat", **args)
    super(**args.merge(animal: animal))
  end
end

Pet.new(name: "Bob") # => #<struct Pet animal="Cat", name="Bob">

这篇关于Ruby Structs 中的命名参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆