Метод определения в Ruby с равными
Будучи новым для Ruby, у меня возникли проблемы с объяснением для себя поведения вокруг определений методов в Ruby.
Пример ниже...
class Foo
def do_something(action)
action.inspect
end
def do_something_else=action
action.inspect
end
end
?> f.do_something("drive")
=> "\"drive\""
?> f.do_something_else=("drive")
=> "drive"
Первый пример является самоочевидным. То, что я пытаюсь понять, - это поведение второго примера. Кроме того, что выглядит как производящий строковый литерал, а другой - нет, что на самом деле происходит? Почему я должен использовать один над другим?
Ответы
Ответ 1
Как правило, do_something
является геттером, а do_something=
- сеттер.
class Foo
attr_accessor :bar
end
эквивалентно
class Foo
def bar
@bar
end
def bar=(value)
@bar = value
end
end
Чтобы ответить на ваш вопрос о различии в поведении, методы, заканчивающиеся на =
, всегда возвращают правую часть выражения. В этом случае возврат action
, а не action.inspect
.
class Foo
def do_something=(action)
"stop"
end
end
?> f = Foo.new
?> f.do_something=("drive")
=> "drive"
Ответ 2
Оба ваших метода на самом деле определяются и называются методами. Довольно много вещей в Ruby можно определить как методы, даже такие операторы, как +
, -
, *
и /
. Ruby позволяет использовать три специальных суффикса для обозначения. Я сам сделал эту фразу. То, что я подразумеваю под нотационными суффиксами, - это то, что в конце метода указывается, как этот метод должен работать.
Взрыва!
Первый нотационный суффикс !
. Это указывает на то, что метод должен быть разрушительным, что означает, что он изменяет объект, на который он вызвал. Сравните выходные данные этих двух скриптов:
a = [1, 2, 3]
a.map { |x| x * x }
a
и
a = [1, 2, 3]
a.map! { |x| x * x }
a
Там между двумя сценариями разница в одном символе, но они действуют по-разному! Первый будет по-прежнему проходить через каждый элемент массива и выполнять операцию внутри блока, но объект в a
по-прежнему будет тем же самым [1,2,3]
, с которого вы начали.
Во втором примере, однако, a
в конце будет [1, 4, 9]
, потому что map!
изменяет объект на месте!
Query
Второй нотационный суффикс ?
, и это указывает, что метод используется для запроса объекта о чем-то и означает, что метод должен возвращать true
, false
или в некотором экстремальные обстоятельства, nil
.
Теперь обратите внимание, что метод не должен возвращать true
или false
... это просто очень хорошо, если бы он это сделал!
Доказательство:
def a?
true
end
def b?
"moo"
end
Вызов a?
вернет true
, а вызов b?
вернет "moo". Так вот, эти методы запросов. Методы, которые должны возвращать true
или false
, но иногда могут возвращать другие вещи, потому что некоторым разработчикам не нравятся другие разработчики.
Инкубационный!
СЕЙЧАС мы получаем мясо вашего (перефразируемого) вопроса: что означает =
в конце метода?
Это обычно указывает, что метод собирается установить определенное значение, поскольку Erik уже обрисован до того, как я закончил написание этого эссе ответа.
Однако он может не устанавливать его так же, как методы запроса могут не возвращать true
или false
. Это просто соглашение.
Вы также можете вызвать этот метод setter:
foo.something_else="value"
Или (мой любимый):
foo.something_else = "value"
В теории вы можете игнорировать переданное значение, так же как вы можете полностью игнорировать любые аргументы, переданные в любой метод:
def foo?(*args)
"moo"
end
>> foo?(:please, :oh, :please, :why, :"won't", :you, :use, :these, :arguments, :i, :got, :just, :for, :you, :question_mark?)
=> "moo"
Ruby поддерживает все три синтаксиса для методов setter, хотя очень редко можно увидеть тот, который вы использовали!
Хорошо, я надеюсь, что этот ответ был грубо воспитательным и теперь вы понимаете больше о Ruby. Наслаждайтесь!
Ответ 3
Вы не можете определить возвращаемое значение для методов присваивания. Возвращаемое значение всегда совпадает с переданным значением, так что цепочки присваивания (x = y = z = 3
) всегда будут работать.
Как правило, вы должны опускать скобки при вызове метода, чтобы он вел себя как свойство:
my_value = f.do_something= "drive"
Ответ 4
def do_something_else=action
action.inspect
end
Это определяет метод setter, поэтому do_something_else выглядит так, как будто мы инициализируем атрибут. Таким образом, инициализированное значение передается непосредственно,