2017-02-23 46 views
0

Я просматриваю учебную книгу Rails и видел часть, где он рассказывает о классах. Вот пример:Что определяет, сколько аргументов допустимо при создании класса Ruby?

class Word < String 
    def palindrome? 
    self == self.reverse 
    end 
end 
# w = Word.new('madamimadam') 
# w.palindrome? #=> true 

Здесь я инстанцирован 'madamimadam' в классе Word, в w переменной. Затем я запускаю метод palindrome?.

Я попытался создать другой метод

class SomeClass 
    def some_method 
    self.reverse 
    end 
end 
# s = SomeClass.new('hello') 
# ArgumentError: wrong number of arguments (1 for 0) 

Почему это я не могу дать аргумент "hello" на SomeClass, но я могу сделать это на Word? Я никогда не определял каждый класс, чтобы принимать или не принимать один аргумент.

Дополнительный вопрос: Почему Word ожидает от 0 до 1 аргументов? Где это определено?

w2 = Word.new('hello', 'joe') 
ArgumentError: wrong number of arguments (2 for 0..1) 

ответ

3

Во втором случае, когда вы не укажете родительский класс, родительский класс по умолчанию Object, который наследует initializer from BasicObject, который не принимает никаких аргументов.

В первом случае initializer was inherited from String, который перекрывает инициализатор упомянутый выше, с тем, чтобы принять один дополнительный аргумент (то есть вы можете написать String.new или String.new("foo")). (Можно также взять два именованных аргументы, encoding и capacity, но это рядом с точкой.)

Если вы хотите повторить инициализатору String «s (один дополнительный позиционный аргумент и один необязательный аргумент ключевого слова), вы могли бы написать это :

class MyString 
    def initialize(str="", encoding: nil, capacity: nil) 
    @encoding = str.encoding || Encoding::ASCII_8BIT 
    # ... 
    end 
end 

определить, сколько аргументов new нужно (если определить initialize на Foo с тремя аргументами, вы бы создать экземпляр класса с Foo.new(a, b, c)).

+0

Несколько комментариев по терминологии: 'initialize' не является конструктором. В Ruby нет конструкторов. 'initialize' - это метод, как и любой другой метод. Обычно он вызывается 'Class # new', но это тоже метод, как и любой другой метод. Ближайшей вещью Ruby к конструктору является метод 'Class # allocate' (который также вызывается' Class # new'), но это тоже обычный метод. –

+0

@ JörgWMittag: Мех. Это нечеткий мир. [Wiki] (https://en.wikipedia.org/wiki/Constructor_ (object-oriented_programming) #Ruby) называет его конструктором. С другой стороны, вы правы: задание «конструктор» можно разделить на «распределитель» и «инициализатор», что и делает Ruby под капотом, вызывая 'allocate' и' initialize' от 'new', Objective-C явно указывает на '[[Класс распределения] init]', а Java скрывает выделение и вызывает инициализатор конструктора. Изменен на «initializer», чтобы быть более точным, но он не более или менее заслуживает того, чтобы быть названным «конструктором», чем Java. – Amadan

+0

Я не согласен. В языках, которые имеют четкую концепцию, называемую «конструктор», конструктор - это четкое понятие. В Java, например, конструкторы не являются методами, они имеют разную семантику отправки, чем методы, они имеют разную семантику привязки, чем методы, они имеют разную семантику наследования, чем методы. Они «особенные». Фактически байт-код JVM для вызова конструктора называется 'invokespecial'. В Ruby 'initialize',' allocate' и 'new' - это просто методы, как любой другой метод. В них нет абсолютно ничего особенного.Единственное «странное» ... –