如何更改Struct属性的默认值?

N.N*_*.N. 30 ruby

根据文档,未设置的Struct属性设置为nil:

unset参数默认为nil.

是否可以为特定属性指定默认值?

例如,对于以下Struct

Struct.new("Person", :name, :happy)
Run Code Online (Sandbox Code Playgroud)

我希望该属性happy默认为true而不是nil.我怎样才能做到这一点?如果我这样做

Struct.new("Person", :name, :happy = true)
Run Code Online (Sandbox Code Playgroud)

我明白了

-:1: syntax error, unexpected '=', expecting ')'
Struct.new("Person", :name, :happy = true)
                                    ^
-:1: warning: possibly useless use of true in void context
Run Code Online (Sandbox Code Playgroud)

rin*_*aun 23

这也可以通过将Struct创建为子类并initialize使用默认值覆盖来实现, 如以下示例所示:

class Person < Struct.new(:name, :happy)
    def initialize(name, happy=true); super end
end
Run Code Online (Sandbox Code Playgroud)

一方面,这种方法确实导致了一些样板; 另一方面,它做你正在寻找的美好和简洁.

一个副作用(可能是一个好处或一个烦恼,取决于你的偏好/用例)是你失去默认Struct行为的所有属性的默认行为nil- 除非你明确地设置它们.实际上,name除非您将其声明为,否则上面的示例将生成必需的参数name=nil

  • 无需为其添加其他图层类.你可以覆盖或隐藏initialize方法:`Person = Struct.new(:name,:happy){def initialize(name,happy = true); 超; 结束}` 这个实现的唯一警告是你必须为你要提供默认值的参数前面的每个参数指定`nil`,如果你的属性已经超过5,那么它可能会很乱. (6认同)
  • 另外,当你将`initialize`定义放在一行上时,它会说"超级结束",它感觉很有趣并让我开心:D (4认同)
  • 在这个上同意@konsolebox,加上是一个不好的做法http://www.rubydoc.info/gems/rubocop/0.29.1/RuboCop/Cop/Style/StructInheritance (2认同)

6ft*_*Dan 11

在@ rintaun的示例之后,您还可以使用Ruby 2+中的关键字参数执行此操作

A = Struct.new(:a, :b, :c) do
  def initialize(a:, b: 2, c: 3); super end
end

A.new
# ArgumentError: missing keyword: a

A.new a: 1
# => #<struct A a=1, b=2, c=3> 

A.new a: 1, c: 6
# => #<struct A a=1, b=2, c=6>
Run Code Online (Sandbox Code Playgroud)

UPDATE

现在需要编写如下代码才能工作.

A = Struct.new(:a, :b, :c) do
  def initialize(a:, b: 2, c: 3)
    super(a, b, c)
  end
end
Run Code Online (Sandbox Code Playgroud)


dbe*_*hur 4

@Linuxios 给出了一个覆盖成员查找的答案。这有几个问题:您不能显式地将成员设置为零,并且每个成员引用都会产生额外的开销。在我看来,您实际上只想在使用提供给::newor的部分成员值初始化新的结构对象时提供默认值::[]

这是一个使用附加工厂方法扩展 Struct 的模块,该方法允许您使用散列描述所需的结构,其中键是成员名称,以及在初始化时未提供时默认填充的值:

# Extend stdlib Struct with a factory method Struct::with_defaults
# to allow StructClasses to be defined so omitted members of new structs
# are initialized to a default instead of nil
module StructWithDefaults

  # makes a new StructClass specified by spec hash.
  # keys are member names, values are defaults when not supplied to new
  #
  # examples:
  # MyStruct = Struct.with_defaults( a: 1, b: 2, c: 'xyz' )
  # MyStruct.new       #=> #<struct MyStruct a=1, b=2, c="xyz"
  # MyStruct.new(99)   #=> #<struct MyStruct a=99, b=2, c="xyz">
  # MyStruct[-10, 3.5] #=> #<struct MyStruct a=-10, b=3.5, c="xyz">
  def with_defaults(*spec)
    new_args = []
    new_args << spec.shift if spec.size > 1
    spec = spec.first
    raise ArgumentError, "expected Hash, got #{spec.class}" unless spec.is_a? Hash
    new_args.concat spec.keys

    new(*new_args) do

      class << self
        attr_reader :defaults
      end

      def initialize(*args)
        super
        self.class.defaults.drop(args.size).each {|k,v| self[k] = v }
      end

    end.tap {|s| s.instance_variable_set(:@defaults, spec.dup.freeze) }

  end

end

Struct.extend StructWithDefaults
Run Code Online (Sandbox Code Playgroud)