2012-04-30 2 views
42

Что я хочу:В Ruby, каковы отношения между 'новыми' и 'initialize'? Как вернуть нуль при инициализации?

obj = Foo.new(0) # => nil or false 

Это не работает:

class Foo 
    def initialize(val) 
    return nil if val == 0 
    end 
end 

Я знаю, что в C/C++/Java/C#, мы не можем возвращать значение в конструкторе.

Но мне интересно, возможно ли это в Ruby.

+12

Если это проверка работоспособности, более удобной задачей было бы поднять Исключение, объясняющее * почему * вы не продолжаете инициализацию. Возвращение ноль просто создаст (серьезную) путаницу. Никто никогда не ожидал, что новый экземпляр объекта будет равен нулю;) – d11wtq

+0

В 'C' нет конструкторов. – YoTengoUnLCD

+3

Заметным исключением для оператора @ d11wtq будет 'NilClass.new()'. –

ответ

5

Вы можете что-то вроде этого:

class Foo 

    def self.init(val) 
    new(val) unless val == 0 
    end 

    def initialize(val) 
    #... 
    end 
end 

Пример использования:

obj = Foo.init(0) 
=> nil 
obj = Foo.init(5) 
=> #<Foo:0x00000002970a98> 
+0

В вашем примере это также вызывает новое? – holaSenor

+0

Если вы имеете в виду пример, когда мы вызываем 'init' с 0, то нет,' new' не будет вызываться. – Flexoid

42

Существуют важные различия между этими двумя методами.

new является классом метода, который обычно создает экземпляр класса (это имеет дело с хитрыми вещами, как выделение памяти, что рубин ограждает вас от так что вы не должны получить слишком грязно).

Затем initialize, метод экземпляра, сообщает объекту, чтобы установить его внутреннее состояние в соответствии с запрошенными параметрами.

Любой из них может быть переопределен в зависимости от того, что вы хотите. Например, Foo.new может фактически создать и вернуть экземпляр FooSubclass, если он достаточно умный, чтобы сделать это.

Однако часто лучше делегировать примеры использования, подобные этим, другим методам класса, которые более подробно описывают, что они делают, например Foo.relating_to(bar). Преодолевая ожидания других людей о том, какие методы, например, new, должны делать, это путает людей больше, чем это поможет им в долгосрочной перспективе.

В качестве примера рассмотрим реализацию Singleton, модуля, который позволяет использовать только один экземпляр определенного класса. Он делает метод new частным и предоставляет метод instance, который либо возвращает существующий экземпляр объекта, либо вызывает new, если он еще не был создан.

71

В Ruby, что отношения между 'new' и 'initialize'?

new обычно звонит initialize. Реализация по умолчанию new что-то вроде:

class Class 
    def new(*args, &block) 
    obj = allocate 

    obj.initialize(*args, &block) 
    # actually, this is obj.send(:initialize, …) because initialize is private 

    obj 
    end 
end 

Но вы можете, конечно, изменить это делать все, что вы хотите.

Как вернуть нуль при инициализации?

Что я хочу:

obj = Foo.new(0) # => nil or false 

Это не работает:

class Foo 
    def initialize(val) 
    return nil if val == 0 
    end 
end 

Я знаю, что в C/C++/Java/C#, мы не можем возвращать значение в конструкторе.

Но мне интересно, возможно ли это в Ruby.

Существует не такая вещь, как конструктор в Ruby. Конструкторы не нужны на хорошо продуманном языке. В Ruby существуют только методы и конечно методы могут возвращать значения.

Проблема, которую вы видите, состоит в том, что вы хотите изменить возвращаемое значение одного метода, но вы переопределяете другой метод. Конечно это не работает. Если вы хотите изменить возвращаемое значение метода bar, вы должны переопределить bar, а не какой-либо другой метод.

Если вы хотите изменить поведение Foo::new, то вы должны изменить Foo::new:

class Foo 
    def self.new(val) 
    return nil if val.zero? 
    super 
    end 
end 

Заметим, однако, что это действительно плохая идея, так как он нарушает договор new, который состоит в том, чтобы вернуть полностью инициализированный, полностью функционирующий экземпляр класса.

+0

Правильно ли 'self.new'? Должно ли это не быть «Foo.new»? – Kashyap

+2

'self' * есть *' Foo' там. Попробуйте 'class Foo; p self end # => Foo' –

4

Желающих сделать

class Foo 
    def initialize(val) 
    return nil if val == 0 
    end 
end 

бы для непоследовательного кода.

Если у вас

class Foo 
    def initialize(val) 
    return nil if val == 0 
    @val = val 
    @bar = 42 
    end 
end 

, что вы хотели бы получить обратно, если вы сделали Foo.new(1)? Хотели бы вы 42 (возвращаемое значение для Foo#initialize) или объект foo? Если вы хотите объект foo для Foo.new(1), то почему вы ожидаете return nil сделать Foo.new(0) return nil?

-1

Это решается просто создание переменную объекта следующим образом:

class Foo 
    def initialize(val) 
     @val = val 
     return nil if @val == 0 
    end 
end 
obj = Foo.new(0) 

Output:- 
=>#<Foo:0x1243b8 @val=0> 

Выходной сигнал изменяется в разных компьютерах.

2

Классы в Ruby являются первоклассными объектами - каждый из них является экземпляром класса Class. Когда новый класс определен (обычно с использованием класса Name ... end), объект типа Class создается и присваивается константе (в этом случае имя.). Когда Name.new вызывается для создания нового объекта, новый метод класса в классе запускается по умолчанию, который, в свою очередь, вызывает выделение для выделения памяти для объекта, прежде чем, наконец, вызвать метод инициализации нового объекта. Фазы построения и инициализации объекта являются раздельными, и оба могут быть перегружены. Конструкция выполняется с помощью метода нового класса, инициализация выполняется с помощью метода экземпляра initialize. initialize не является конструктором!

 Смежные вопросы

  • Нет связанных вопросов^_^