如何在Ruby中更改类构造函数的返回值?

时间:2011-02-03 16:31:47

标签: ruby constructor

我有一个班,Foo。我希望能够将构造函数传递给Foo实例,foo并将相同的实例取回。

换句话说,我希望这个测试通过:

class Foo; end

foo = Foo.new
bar = Foo.new(foo)

assert_equal foo, bar

任何人都知道我该怎么做?我试过这个:

class Foo
  def initialize(arg = nil)
    return arg if arg
  end
end

foo = Foo.new
bar = Foo.new(foo)

assert_equal foo, bar  # => fails

但它不起作用。

帮助?

修改

因为有很多人要求我提出理由:

我正在快速分析大量数据(很多TB),我将会有很多对象的实例。对于其中一些对象,使用相同数据的两个不同实例没有意义。例如,一个这样的对象是具有两个属性的“窗口”(如在时间窗口中)对象:开始时间和结束时间。我希望能够以任何这些方式使用构造函数并返回一个窗口对象:

window = Window.new(time_a, time_b)
window = Window.new([time_a, time_b])
window = Window.new(seconds_since_epoch_a, seconds_since_epoch_b)
window = Window.new(window_obj)
window = Window.new(end => time_b, start => time_a)
...

需要窗口的其他一些对象可能会以这种方式实例化:

obj = SomeObj.new(data => my_data, window => window_arg)

我不一定知道window_arg中有什么,我真的不在乎 - 它会接受任何可由Window构造函数解释的参数。在已经有Window实例的情况下,我宁愿只使用该实例。但是解释这个问题的工作似乎是Window构造函数的一个问题。无论如何,正如我所提到的,我正在翻阅许多TB数据并创建大量实例。如果窗口对象被传递,我希望它只是被识别为窗口对象并被使用。

6 个答案:

答案 0 :(得分:29)

通过definition,构造函数意味着返回它们所属的类的新创建的对象,因此,不应该覆盖此行为。

此外,在Ruby中,new在其方法体内的某处调用initialize,并且忽略其返回值,因此从initialize返回的值无论如何都不会从new

话虽如此,我认为在您的情况下,您可能希望创建一个工厂方法,该方法将根据传递给工厂方法的参数返回不同的Foo对象:

class Foo
  def self.factory(arg = nil)
    return arg if arg.kind_of? Foo
    Foo.new
  end
end
foo = Foo.factory
bar = Foo.factory(foo)

assert_equal foo, bar #passes

答案 1 :(得分:17)

def Foo.new(arg=nil)
  arg || super
end

答案 2 :(得分:15)

initialize调用

new,忽略其返回值。基本上,默认的new方法看起来像这样(除了它在C中实现,而不是在ruby中):

class Class
  def new(*args, &blk)
    o = allocate
    o.send(:initialize, *args, &blk)
    o
  end
end

所以无论你在initialize做什么,都会以任何一种方式返回新分配的对象。改变它的唯一方法是覆盖new方法,例如:

class Foo
  def self.new(arg=nil)
    if arg
      return arg
    else
      super
    end
  end
end

但是我强烈反对这一点,因为它与人们在致电new时的许多期望背道而驰:

  • 人们期望new返回一个新对象。我的意思是它甚至被称为new。如果你想要一个并不总是创建一个新对象的方法,你应该把它称之为其他东西。
  • 至少人们希望Foo.new返回Foo个对象。您的代码将返回任何参数。即Foo.new(42)将返回42,一个整数,而不是Foo个对象。因此,如果你要这样做,你应该至少只返回给定的对象,如果它是Foo对象。

答案 3 :(得分:2)

不起作用:


class Some
    def self.new( str )
        SomeMore.new( str )
    end
end

# the Some is parent of SomeMore class SomeMore < Some def initialize( str ) @str = str end end

答案 4 :(得分:0)

对于这个特定用例,最好使用其中一种方法。

Class Foo
    def self.new(args=nil)
        @@obj ||= super(args)
    end
end


Class Foo
    def self.new(args)
      @@obj = super(args)
    end

    def self.new
      @@obj
    end
end

这允许您只创建一个可以普遍使用的对象,但返回一个Foo对象,使其更符合new方法的标准期望,如雅各布指出。

答案 5 :(得分:0)

我偶然发现了这个问题,并且效果很好。说您想要一个构造函数(无论出于何种原因)以返回浮点数:

class Decimal
   # possibly a bug that this works
   @@value =
   def self.new(input)
      if input.class == Integer
         @@value = input.to_f
      elsif input.class == Float
         @@value = input
      else
         @@value = -1.0
      end
   end
end
x = Decimal.new(4)
y = Decimal.new(32.141)
puts x # 4.0
puts y # 32.141

或者就您而言,Foo:

class Foo
   @@value = 
   def self.new(args)

      # some code ...

      @@value = Foo.new #:<= your return value goes here
   end
end