How to change the default value of a Struct attribute?

后端 未结 6 1405
孤城傲影
孤城傲影 2020-12-17 07:43

According to the documentation unset attributes of Struct are set to nil:

unset parameters default to nil.

Is it po

6条回答
  •  情书的邮戳
    2020-12-17 08:32

    @Linuxios gave an answer that overrides member lookup. This has a couple problems: you can't explicitly set a member to nil and there's extra overhead on every member reference. It seems to me you really just want to supply the defaults when initializing a new struct object with partial member values supplied to ::new or ::[].

    Here's a module to extend Struct with an additional factory method that lets you describe your desired structure with a hash, where the keys are the member names and the values the defaults to fill in when not supplied at initialization:

    # 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       #=> # #
      # MyStruct[-10, 3.5] #=> #
      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
    

提交回复
热议问题