2015-10-07 1 views
-1

Я пытаюсь присвоить функцию переменной, он чувствует себя так естественно, чтобы сделать это:Ruby (NoMethodError) из-за передачи аргумента

def myfunction(num=3) 
    num 
end 

varfunc = myfunction 

puts varfunC# it outputs 3 here, as expected 

Но это не так просто ...

puts varfunc(12) 

дает мне эту консоль Ошибка:

test.rb:8:in `<main>': undefined method `varfunc' 
for main:Object (NoMethodError) 

Как аргументы быть переданы тогда? Большое спасибо.

ответ

3

I'm trying to assign a function to a variable, it feels so natural to do this:

def myfunction(num=3) 
    num 
end 

varfunc = myfunction 

puts varfunC# it outputs 3 here, as expected 

В этом есть несколько ошибок.

Во-первых, myfunction не является функцией, это метод. Методы не являются объектами в Ruby. Вы можете назначать объекты только переменным, поэтому, поскольку методы не являются объектами, вы не можете назначать их переменным.

Во-вторых, вы не назначаем метод myfunction переменной varfunc, потому что, как я уже говорил выше, вы не можете сделать это. Вы являетесь , вызывая метод myfunction и присваивая его возвращаемое значение переменной varfunc. В Ruby круглые скобки необязательны для вызовов методов.

В-третьих, даже если это сделал работу, как вы ожидаете его, т.е. если методы были объектами (которые они не являются), то код, который вы показали до сих пор не должны работать так, как вы видите Это. Еслиvarfuncбыли функция, то код будет не «выход 3 здесь, как и ожидалось», потому что можно было бы ожидать varfunc быть функцией, не является целым числом, и должны вывести что-то вроде

#<Function:0xdeadbeef4815162342> 

Таким образом, тот факт, что он делает выход 3 не ожидается, а на самом деле ясно говорит вам, что ваши ожидания неправильно.

Ваша логика противоречива: в строке 5, вы предполагаете, что убрав скобку будет не вызов myfunction, но вместо того, чтобы ссылаться на него, в строке 7, вы предполагаете, что уход от скобок будет хотение не ссылки varfunc , но вместо этого назовите его. Это бессмысленно.

varfunc - это переменная, а не метод. Вы можете передавать аргументы только методам, а не переменным. Вам нужно сделать метод varfunc.

Есть два способа приблизиться к этому.Одним из способов были бы сделать myfunction на Proc объект, который является ближайшим эквивалентом рубин имеет к «функции»:

myfunction = -> (num=3) { num } 

varfunc = myfunction 

puts varfunc 
# #<Proc:[email protected](irb):1 (lambda)> 
# *This* is the output you would expect from `puts`ing a "function" 

puts varfunc.() 
# 3 

puts varfunc.(12) 
# 12 

Другая возможность была бы использовать отражение для получения объекта Method обертки для метода myfunction, используя метод Object#method:

def myfunction(num=3) num end 

varfunc = method(:myfunction) 

puts varfunc 
# #<Method: Object#myfunction> 

puts varfunc.() 
# 3 

puts varfunc.(12) 
# 12 
+0

Большое спасибо! Довольно иллюстративный ответ. То, что я пытался сделать, было похоже на Python, где я могу просто назначить функцию переменной и просто использовать ее в качестве исходной функции. Дело в скобках заключается в том, что я прочитал, что в Ruby вы можете оставить их и передать аргументы, разделенные запятыми, поэтому я сделал это. – otrebla

+1

Да, * точно *, вы можете оставить круглые скобки, и он все равно вызовет метод. Скобки являются необязательными. Тем не менее, в вашем исходном коде вы оставили круглые скобки * дважды *, ожидали две вещи * разных вещей: в первый раз, когда вы ожидали, что он будет действовать как Python, где скобки * обязательны для вызовов и оставляют их просто ссылки функция. В то время как во второй раз вы ожидали, что функция будет вызвана *, несмотря на то, что * оставит скобки. Другими словами, логика внутри вашего кода была внутренне непоследовательной. Исчезновение этой непоследовательности было бы ... –

+0

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