Как изменить возвращаемое значение конструктора класса в Ruby?
у меня занятия, Фу. Я хочу иметь возможность передать конструктору экземпляр 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
но это не работает.
помочь?
редактировать
потому что ряд людей попросили мое обоснование:
Я делаю быстрый анализ лотов данных (много ТБ), и у меня будет много экземпляров многих объектов. Для некоторых из этих объектов не имеет смысла иметь два разных экземпляра с одинаковыми данными. Например, одним из таких объектов является объект" окно " (как во временном окне), который имеет два свойства: время начала и время окончания. Я хочу иметь возможность использовать конструктор любым из этих способов и вернуть объект window:
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 передается вокруг, я хочу, чтобы он просто был распознан как объект окна и использовался.
5 ответов
By определение, конструкторы предназначены для возврата вновь созданного объекта класса, членом которого они являются, поэтому вы не должны не переопределить это поведение.
кроме того, в 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
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
возвратить
не работает:
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
для этого конкретного случая использования, возможно, было бы лучше использовать один из этих подходов.
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
метод, как указал Джейкоб.