简体   繁体   English

如何在 ruby 中拥有多个构造函数?

[英]How can I have more than one constructor in ruby?

I want to have more than one constructor in Ruby.我想在 Ruby 中有多个构造函数。 I know that I have to use self methods, but the thing is that I don't know how to implement them.我知道我必须使用 self 方法,但问题是我不知道如何实现它们。 For example:例如:

def initialize(n1 = 0,n2 = 0,n3 = 0)
  @num1 = n1
  @num2 = n2
  @num3 = n3
end

def self.MyClass(num1, num3)
...
end

def self.MyClass(num2,num3)
 ...
end

So in the first case what I want to do is to only give a value to num1 and num3, not to num2.所以在第一种情况下,我想做的是只给 num1 和 num3 一个值,而不是给 num2。 And in the second case I want to give a value only to num2 and num3, but not to num1.在第二种情况下,我只想给 num2 和 num3 赋值,而不是给 num1。 How can I do that?我怎样才能做到这一点?

Couldn't you achieve what you want by using keyword arguments:难道你不能通过使用关键字 arguments 来实现你想要的:

class MyClass
  attr_reader :num1, :num2, :num3
  def initialize(n1: nil, n2: nil, n3: nil)
    if n2.nil?
      puts 'num2 is nil'
    end
    if n3.nil?
      puts 'num3 is nil'
    end
    @num1 = n1 || 0
    @num2 = n2 || 0
    @num3 = n3 || 0
  end
end

MyClass.new(n1: 1, n2: 3)
# num3 is nil
# => <MyClass:0x0... @num1=1, @num2=3, @num3=0>

MyClass.new(n1: 4, n3: 1)
# num2 is nil
# => <MyClass:0x0... @num1=4, @num2=0, @num3=1>

Keyword arguments are available since ruby 2.0.关键字 arguments 自 ruby 2.0 起可用。 Google or see for instance here for more information regarding keyword arguments.谷歌或查看例如这里有关关键字 arguments 的更多信息。

If you want to stay close to the MyClass() syntax, you could set it up like this:如果你想保持接近 MyClass() 语法,你可以这样设置:

class MyClass
  attr_reader :num1, :num2, :num3
  def initialize(n1 = 0, n2 = 0, n3 = 0)
    @num1 = n1
    @num2 = n2
    @num3 = n3
  end
  def self.call(n1: nil, n2: nil, n3: nil)
    if n2.nil?
      puts 'num2 is nil'
    end
    if n3.nil?
      puts 'num3 is nil'
    end
    new n1, n2, n3
  end
end

MyClass.(n1: 1, n2: 3)
# num3 is nil
# => <MyClass:0x0... @num1=1, @num2=3, @num3=nil>
MyClass.(n1: 4, n3: 1)
# num2 is nil
# => <MyClass:0x0... @num1=4, @num2=nil, @num3=1>

Note the '.'注意“。” after the class name.在 class 名称之后。

Yet another alternative is to use def self.[](...) instead of def self.call(...) and make your calls use MyClass[...] (no dot after class).另一种选择是使用def self.[](...)而不是def self.call(...)并使您的呼叫使用MyClass[...] (课后没有点)。

Ruby semantics about constructors aside (and Jörg's comments about that are precisely correct, as usual), you have said that you want to create a class where you give a value to different attributes in different instances of the class, and not to all of them in any given instance.除了关于构造函数的 Ruby 语义(以及 Jörg 对此的评论是完全正确的,像往常一样),您已经说过您想要创建一个 class 在其中您为 ZA2F2ED4F8EBC2CBB4C21 的不同实例中的不同属性赋值,而不是所有在任何给定的情况下。

You don't have to use "self methods" (Ruby calls them "class methods") to do that, and you certainly don't need "more than one constructor" to do that.您不必使用“self 方法”(Ruby 称它们为“类方法”)来做到这一点,当然也不需要“多个构造函数”来做到这一点。 Just give a default value of nil to each of them.只需给他们每个人一个默认值nil Pretty similar to what you already have:与您已经拥有的非常相似:

def initialize(n1 = nil, n2 = nil, n3 = nil)
  @num1 = n1
  @num2 = n2
  @num3 = n3
end

Now, if you don't set them when you initialize the instance, their value will be nil , and if you need to, you can test for that in your methods.现在,如果您在初始化实例时没有设置它们,它们的值将为nil ,如果需要,您可以在您的方法中进行测试。

You haven't really explained the problem that you're trying to solve (you haven't said why you want to have some instances have some attributes and other instances have other ones), so I can't really tell you whether that's a solution to it.您还没有真正解释您要解决的问题(您还没有说为什么要让某些实例具有某些属性而其他实例具有其他属性),因此我无法真正告诉您这是否是解决方案。 But that's the easiest way to do what you say you want to do.但这是做你说你想做的最简单的方法。 If you explain why you want to do it, maybe we can come up with something better.如果您解释为什么要这样做,也许我们可以想出更好的方法。

To dynamic your class constructor, I think you need to dynamic attr_accessor of your instance variables too.要动态化您的 class 构造函数,我认为您也需要动态attr_accessor实例变量。
Because we need to know which instance variables are initialized then we should declare attr_accessor inside initialize block.因为我们需要知道初始化了哪些实例变量,所以我们应该在initialize块中声明attr_accessor
I already check this and it works well, you can give it a try here:我已经检查过了,效果很好,你可以在这里试一试:

class MultipleConstructors
  def initialize(args={})
    args.each do |k,v|
      instance_variable_set("@#{k}", v)
      self.class.send(:attr_accessor, *args.keys)
    end
  end
end

And then you can get or set any instance variable after initialize constructor.然后您可以在初始化构造函数之后获取或设置任何实例变量。

m = MultipleConstructors.new(a: 1, c: 4)
m2 = MultipleConstructors.new(d: 'blah', e: 100)
m3 = MultipleConstructors.new(f: true)

or you can initialize any constructor you want...或者你可以初始化任何你想要的构造函数......
ref: https://apidock.com/ruby/Module/attr_accessor参考: https://apidock.com/ruby/Module/attr_accessor

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM