2017-04-08 3 views
1

Betrachten Sie den folgenden Code-Schnipsel:Elixir - Capture-Wert von Lambda

def capture 
    Functor.function(fn(value) -> ??? end) 
    ??? 
end 
  • angenommen, dass das Lambda genau einmal
  • sicher

genannt bekommt Was die bevorzugte Art und Weise wäre das zu erfassen erstes Argument der Lambda fn(value) in einer Weise, dass es die Rückkehr von capture Methode sein kann?

+0

Nicht sicher, dass ich die Frage verstehe. Sie möchten "Wert" von "Capture" zurückgeben? Was, wenn dieses Fn nicht einmal aufgerufen wird? und was, wenn dieses Fn mehr als einmal aufgerufen wird? – Dogbert

+1

@Dogbert Versucht, zu den von Ihnen angesprochenen Problemen zu klären, danke für die Rückmeldung! Liebte deinen Nick;) – Kalecser

Antwort

4

Sie brauchen hier eine Form von veränderbaren Zustand. Der einfachste Weg ist die Verwendung Agent:

defmodule Functor do 
    def function(f) do 
    f.(:hey) 
    end 

    def capture do 
    {:ok, agent} = Agent.start_link(fn -> nil end) 
    Functor.function(fn(value) -> 
     Agent.update(agent, fn _ -> value end) 
    end) 
    Agent.get(agent, &(&1)) 
    end 
end 

IO.inspect Functor.capture() 

Ausgang:

:hey 

Einige Dinge zu beachten:

Wenn die fn nie genannt wird, werden Sie den Anfangswert des Agenten erhalten (nil im obigen Code).

Wenn das Fn mehr als einmal aufgerufen wird, erhalten Sie den Wert des letzten Anrufs. Mit ein wenig Modifikation können Sie sogar alle Werte erfassen, wenn Sie das wollen.


Edit: Da Sie nur das für die Prüfung verwendet ist erwähnt, gibt es eine andere ist, viel prägnante Weise. Senden Sie eine Nachricht an sich selbst von der FN und bestätigen Sie mit assert_receive:

test "the truth" do 
    pid = self() 
    Functor.function(&send(pid, &1)) 
    assert_receive :hey 
end 
+0

Danke für die tolle Antwort! Ich habe bereits einen Agenten benutzt, wollte aber sicher sein, dass das der bevorzugte Weg ist. Wir verwenden diese Technik derzeit nur zum Schreiben von Komponententests. Ich gehe davon aus, dass wir dies nur selten in der Produktion verwenden werden. – Kalecser

+2

Bitte beachten Sie meine Bearbeitung für einen besseren/kürzeren Weg, wenn dies nur zum Testen ist! – Dogbert

+0

Vielen Dank für das Update, in der Tat für einfache Fälle assert_receive wäre die bevorzugte Lösung. ;) – Kalecser