如何在Ruby中生成初始化器?

8

现在是时候让它更简短了:

class Foo
  attr_accessor :a, :b, :c, :d, :e

  def initialize(a, b, c, d, e)
    @a = a
    @b = b
    @c = c
    @d = d
    @e = e
  end
end

我们有'attr_accessor'来生成getter和setter。
我们有什么可以根据属性生成初始化程序的东西吗?

1
可能是在Ruby中创建对象的惯用方法的重复问题。 - Andrew Grimm
def initialize(*args) ... @a,@b,@c,@d,@e = argsdef initialize(*args) ... @a,@b,@c,@d,@e = args - Muhammad Umer
5个回答

15

最简单的:

Foo = Struct.new( :a, :b, :c )

生成访问器和初始化器。您可以使用以下方式进一步自定义您的类:

Foo = Struct.new( … ) do
  def some_methodend
end

1
这很不错。我以前从未想过在那个目的上使用结构体。当然,它有局限性,比如无法从其他一些类继承。 - d11wtq
5
你也可以使用 class Foo < Struct.new(:a, :b, :c) 进行定义。 - Andrew Marshall
@d11wtq 你可以从一个结构体继承或者继承到一个结构体。 - steenslag
@Andrew 很好,我以前从没想过这样做。 - Phrogz

2
我们可以像这样创建类似于def_initializer的东西:
# Create a new Module-level method "def_initializer"
class Module
  def def_initializer(*args)
    self.class_eval <<END
      def initialize(#{args.join(", ")})
        #{args.map { |arg| "@#{arg} = #{arg}" }.join("\n")}
      end
END
  end
end

# Use it like this
class Foo
  attr_accessor   :a, :b, :c, :d
  def_initializer :a, :b, :c, :d

  def test
    puts a, b, c, d
  end
end

# Testing
Foo.new(1, 2, 3, 4).test

# Outputs:
# 1
# 2
# 3
# 4

1
+1 是使用 eval 的字符串形式来要求正确的元数。你可能应该将此方法放在 ModuleClass 的单例类上,因为除了类之外的对象实例上使用这个方法没有太多意义。 - Phrogz

1
你可以使用像constructor这样的gem。从描述中可以看出:

声明式意味着通过将哈希传递给构造函数来定义对象属性,该函数将设置相应的ivars。

它很容易使用:
Class Foo
  constructor :a, :b, :c, :d, :e, :accessors => true
end

foo = Foo.new(:a => 'hello world', :b => 'b',:c => 'c', :d => 'd', :e => 'e')
puts foo.a # 'hello world'

如果您不想使用访问器生成ivars,可以省略:accessors => true

希望这可以帮到您 /Salernost


1
class Module
  def initialize_with( *names )
    define_method :initialize do |*args|
      names.zip(args).each do |name,val|
        instance_variable_set :"@#{name}", val
      end
    end
  end
end

1
这很不错,但它将跳过正常的“initialize”参数检查:initialize_with:a,:b + Foo.new(1,2,3,4,5)将不会产生错误。 - Casper

-1
class Foo
  class InvalidAttrbute < StandardError; end

  ACCESSORS = [:a, :b, :c, :d, :e]
  ACCESSORS.each{ |atr| attr_accessor atr }

  def initialize(args)
    args.each do |atr, val|
      raise InvalidAttrbute, "Invalid attribute for Foo class: #{atr}" unless ACCESSORS.include? atr
      instance_variable_set("@#{atr}", val)
    end
  end
end

foo = Foo.new(a: 1)
puts foo.a
#=> 1

foo = Foo.new(invalid: 1)
#=> Exception

我认为开头的句子大概是“是时候把它变短了” ;) - d11wtq
是的。但是在底层,结构体执行的操作基本相同 :) - fl00r

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接