2012-01-02 2 views
8

У меня есть метод с необязательным аргументом. Как я могу решить, был ли аргумент предоставлен или нет?Как решить, был ли предоставлен необязательный аргумент в рубиновом методе

Я придумал следующие решения. Я задаю этот вопрос, потому что я не совсем доволен ни одним из них. Существует ли там лучший?

nil в качестве значения по умолчанию

def m(a= nil) 
    if a.nil? 
     ... 
    end 
end 

Недостатком этого является то, что оно не может быть принято решение не было ли дано никаких аргументов или nil.

NoArgument обычай в качестве значения по умолчанию

class NoArgument 
end 

def m(a= NoArgument.new) 
    if NoArgument === a 
     ... 
    end 
end 

ли nil был дан может быть решена, но та же проблема существует для экземпляров NoArgument.

Оценка размера многоточие

def m(*a) 
    raise ArgumentError if m.size > 1 
    if m.size == 1 
     ... 
    end 
end 

В этом варианте он может быть всегда принято решение, было ли дано дополнительный аргумент. Однако Proc#arity этого метода изменился с 1 на -1 (не верно, см. Комментарий). У него все еще есть недостаток, заключающийся в ухудшении документирования и необходимости вручную поднять ArgumentError.

+1

Параметр 'arity' всех ваших методов' -1'. Единственным недостатком последнего решения является то, что вы должны вручную проверить, что дано не более одного аргумента, и необходима документация, чтобы знать, что такое аргументы. –

ответ

15

Йорг W Mittag имеет following code snippet, что может делать то, что вы хотите:

def foo(bar = (bar_set = true; :baz)) 
    if bar_set 
    # optional argument was supplied 
    end 
end 
+0

Какой будет прецедент для этого? – AndrewF

+1

@AndrewF: На этот вопрос лучше ответить Йоханнес или Йорг W Миттаг. –

+0

В основной библиотеке есть несколько методов, которые ведут себя по-разному в зависимости от количества предоставленных аргументов. По сути, они имитируют отправку на основе аргументов. В большинстве реализаций Ruby эти методы реализованы в C, C++, Java, C# и т. Д., И они имеют привилегированный доступ к внутренним компонентам Ruby, поэтому они * могут * фактически просто проверять количество аргументов. Но если вы хотите написать совместимый метод в Ruby, вам нужно прибегнуть к трюкам, подобным этому. –

4

Как насчет

NO_ARGUMENT = Object.new 

def m(a = NO_ARGUMENT) 
    if a.equal?(NO_ARGUMENT) 
     #no argument given 
    end 
end 
+0

Это метод, используемый, например, Rubinius. –

+1

Единственным недостатком этого подхода является то, что метод может принять решение передать NO_ARGUMENT в качестве аргумента другому методу, используя эту идиому. –

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