2012-01-02 6 views
8

Mam metodę z opcjonalnym argumentem. Jak mogę zdecydować, czy argument został podany, czy nie?Jak zdecydować, czy opcjonalny argument został podany, czy nie, w metodzie ruby ​​

Wymyśliłem następujące rozwiązania. Zadaję to pytanie, ponieważ nie jestem w pełni zadowolony z żadnego z nich. Czy istnieje lepszy?

nil jako wartości domyślnej

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

Wadą Ten jest, że nie może zostać podjęta decyzja, czy żaden argument lub nil została podana.

zwyczaj NoArgument jako wartości domyślnej

class NoArgument 
end 

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

czy nil dano może zostać podjęta decyzja, ale występuje ten sam problem dla wystąpień NoArgument.

Oceniając wielkość wielokropkiem

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

W tym wariancie może to być zawsze podjęta decyzja, czy opcjonalny argument został podany. Jednak metoda Proc#arity zmieniła się z 1 na -1 (nieprawda, patrz komentarz). Wadą jest to, że dokumentacja jest gorsza i trzeba ręcznie podnieść ArgumentError.

+1

Opcja 'arity' wszystkich swoich metod jest' -1'. Jedyną wadą ostatniego rozwiązania jest to, że trzeba ręcznie sprawdzić, czy podano nie więcej niż jeden argument i potrzebna jest dokumentacja, aby wiedzieć, jakie są argumenty. –

Odpowiedz

15

Jorg W Mittag ma following code snippet że może robić to, co chcesz:

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

Jaki byłby w tym przypadek? – AndrewF

+1

@AndrewF: Na to pytanie lepiej odpowiedzą johannes lub Jorg W Mittag. –

+0

Istnieje kilka metod w bibliotece rdzenia, które zachowują się inaczej w zależności od liczby dostarczonych argumentów. W efekcie symulują wysyłkę opartą na argumentach. W większości implementacji Ruby metody te są implementowane w C, C++, Java, C# itd. I mają uprzywilejowany dostęp do wewnętrznych elementów Ruby, więc * mogą * faktycznie sprawdzić liczbę argumentów. Ale jeśli chcesz napisać kompatybilną metodę w Ruby, musisz uciekać się do takich sztuczek. –

4

Jak o

NO_ARGUMENT = Object.new 

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

Taką metodę stosuje na przykład Rubinius. –

+1

Jedyną wadą tego podejścia jest to, że metoda może zdecydować o przekazaniu "NO_ARGUMENT" jako argumentu do innej metody wykorzystującej ten idiom. –

Powiązane problemy