【问题标题】:What is the most efficient way to initialize a Class in Ruby with different parameters and default values?用不同的参数和默认值在 Ruby 中初始化类的最有效方法是什么?
【发布时间】:2011-06-01 01:24:25
【问题描述】:

我想要一个类和一些属性,您可以在初始化期间设置或使用其默认值。

class Fruit
  attr_accessor :color, :type
  def initialize(color, type)
    @color=color ||= 'green'
    @type=type ||='pear'
  end
end

apple=Fruit.new(red, apple)

【问题讨论】:

    标签: ruby oop class


    【解决方案1】:

    解决此问题的典型方法是使用具有默认值的哈希。如果哈希是方法的最后一个参数,Ruby 有一个很好的语法来传递哈希值。

    class Fruit
      attr_accessor :color, :type
    
      def initialize(params = {})
        @color = params.fetch(:color, 'green')
        @type = params.fetch(:type, 'pear')
      end
    
      def to_s
        "#{color} #{type}"
      end
    end
    
    puts(Fruit.new)                                    # prints: green pear
    puts(Fruit.new(:color => 'red', :type => 'grape')) # prints: red grape
    puts(Fruit.new(:type => 'pomegranate')) # prints: green pomegranate
    

    这里有一个很好的概述:http://deepfall.blogspot.com/2008/08/named-parameters-in-ruby.html

    【讨论】:

    • 我最喜欢这个解决方案。原因是我们不需要创建任何更重要的对象(例如想象一个大类实例),以防参数已经具有这些选项。但我也想使用更简洁的语法(只是我的意见):@color = params[:color] || '绿色'
    • 我将有机会做一点 ruby​​/jruby! 7年后!
    【解决方案2】:

    从 Ruby 2.0 开始支持命名或关键字参数。

    你可以使用:

    class Fruit
      attr_reader      :color, :type
    
      def initialize(color: 'green', type: 'pear')
        @color = color
        @type = type
      end
    
      def to_s
        "#{color} #{type}"
      end
    end
    
    puts(Fruit.new)                                    # prints: green pear
    puts(Fruit.new(:color => 'red', :type => 'grape')) # prints: red grape
    puts(Fruit.new(:type => 'pomegranate')) # prints: green pomegranate
    

    关于这个主题的一些有趣的笔记:

    【讨论】:

    • 明确地说,这是迄今为止最好的答案,尽管正如 knut 所说,kwargs 直到 Ruby 2.0 才可用。
    【解决方案3】:

    Brian 的回答非常好,但我想建议一些修改,使其主要是元:

    class Fruit
    
      # Now this is the only thing you have to touch when adding defaults or properties
      def set_defaults
        @color ||= 'green'
        @type  ||= 'pear'
      end
    
      def initialize(params = {})
        params.each { |key,value| instance_variable_set("@#{key}", value) }
        set_defaults
        instance_variables.each {|var| self.class.send(:attr_accessor, var.to_s.delete('@'))}
      end
    
      def to_s
        instance_variables.inject("") {|vars, var| vars += "#{var}: #{instance_variable_get(var)}; "}
      end
    
    end
    
    puts Fruit.new
    puts Fruit.new :color => 'red', :type => 'grape'  
    puts Fruit.new :type => 'pomegranate'
    puts Fruit.new :cost => 20.21
    puts Fruit.new :foo => "bar"
    
    
    f = Fruit.new :potato => "salad"
    puts "f.cost.nil? #{f.cost.nil?}"
    

    哪些输出:

    @color: green; @type: pear; 
    @color: red; @type: grape; 
    @color: green; @type: pomegranate; 
    @color: green; @type: pear; @cost: 20.21; 
    @color: green; @type: pear; @foo: bar; 
    f.cost.nil? true
    

    当然,这并不是所有事情的完美解决方案,但它为您提供了一些关于使您的代码更加动态的想法。

    【讨论】:

    • 谢谢!我以后可能会考虑切换到这个。
    • @l1x 很高兴我能帮上忙。如果信息有帮助,投票会很酷。 ;)
    【解决方案4】:

    我会这样做:

    class Fruit
      attr_accessor :color, :type
    
      def initialize(args={})
        options = {:color => 'green', :type => 'pear'}.merge(args)
    
        self.color = options[:color]
        self.type  = options[:type]
      end
    end
    
    apple = Fruit.new(:color => 'red', :type => 'apple')
    

    这样,您永远不必担心缺少参数(或它们的顺序),并且您将始终拥有默认值。 .merge 当然会覆盖默认值(如果存在)。

    【讨论】:

      【解决方案5】:

      我喜欢 vonconrad 的回答,但会有一个单独的 defaults 方法。也许它在代码行数方面效率不高,但它更能揭示意图并且涉及更少的认知开销,而更少的认知开销意味着更高效的开发人员入职。

      class Fruit
        attr_accessor :color, :type
      
        def initialize(args={})
          options = defaults.merge(args)
      
          @color = options.fetch(:color)
          @type  = options.fetch(:type)
        end
      
        def defaults
          {
            color: 'green',
            type:  'pear'
          }
        end
      end
      
      apple = Fruit.new(:color => 'red', :type => 'apple')
      

      【讨论】:

        【解决方案6】:

        更简单的方法:

        class Fruit
          attr_accessor :color, :type
          def initialize(color = 'green', type = 'pear')
            @color = color
            @type = type
          end
          def to_s
            "#{color} #{type}"
          end
        end
        
        
        puts Fruit.new # prints: green pear
        puts Fruit.new('red','apple') # prints: red apple
        puts Fruit.new(nil,'pomegranate') # prints: green pomegranate
        

        【讨论】:

        • 是的,除了这种方法要求您按顺序传递参数。使用散列方法,您必须指定参数名称(即散列键),但您可以按任意顺序传递这些键。
        【解决方案7】:

        更美味的语法糖:

        class Fruit
          attr_accessor :color, :type
          def initialize *args
            @color, @type = args 
          end
        end
        
        pear = Fruit.new 'green', :pear
        

        【讨论】:

        • 这不允许你设置默认值。
        猜你喜欢
        • 1970-01-01
        • 2010-10-02
        • 1970-01-01
        • 1970-01-01
        • 2011-08-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-04-17
        相关资源
        最近更新 更多