Was ist der Unterschied zwischen => , ()=> und Unit=>
Ich versuche darstellen, eine Funktion, die keine Argumente entgegennimmt und keinen Wert zurückgibt (ich bin die Simulation der setTimeout-Funktion in JavaScript, wenn Sie müssen wissen.)
case class Scheduled(time : Int, callback : => Unit)
nicht kompilieren, zu sagen "`val' - Parameter kann nicht sein, call-by-name"
case class Scheduled(time : Int, callback : () => Unit)
kompiliert, hat aber geltend gemacht werden, komischerweise, statt
Scheduled(40, { println("x") } )
Habe ich dazu
Scheduled(40, { () => println("x") } )
Was auch funktioniert, ist
class Scheduled(time : Int, callback : Unit => Unit)
aber ist aufgerufen, in einer noch-weniger-sinnvolle
Scheduled(40, { x : Unit => println("x") } )
(Was wäre eine variable vom Typ Einheit sein?) Was ich wollen natürlich ist ein Konstruktor, der sein kann, berufen sich auf die Weise würde ich es aufrufen, wenn es eine gewöhnliche Funktion:
Scheduled(40, println("x") )
Geben baby seine Flasche!
Eine weitere Möglichkeit zur Verwendung von case-Klassen mit Namen parms, ist, um Sie in einer sekundären parameter-Liste, z.B.
Ein paar weitere interessante Aspekte in Bezug auf die Unterschiede zwischen by-name-Parameter und 0-arheit-Funktionen sind in diese Frage und die Antwort. Es ist eigentlich das, was ich suchte, als ich fand diese Frage.
case class Scheduled(time: Int)(callback: => Unit)
. Dies funktioniert, da die sekundären parameter Liste ist nicht öffentlich bloßgestellt, noch ist es enthalten in der generierten equals
/hashCode
Methoden.Ein paar weitere interessante Aspekte in Bezug auf die Unterschiede zwischen by-name-Parameter und 0-arheit-Funktionen sind in diese Frage und die Antwort. Es ist eigentlich das, was ich suchte, als ich fand diese Frage.
InformationsquelleAutor Malvolio | 2010-12-28
Du musst angemeldet sein, um einen Kommentar abzugeben.
Call-by-Name: => Typ
Den
=> Type
notation steht für call-by-name, das ist einer der viele Möglichkeiten Parameter übergeben werden können. Wenn Sie nicht vertraut mit Ihnen, empfehle ich, sich etwas Zeit zu Lesen, dass wikipedia-Artikel, obwohl heutzutage ist es meistens call-by-value und call-by-reference.Was es bedeutet, ist, dass das, was vergangen ist ersetzt für den Wert name in der Funktion. Nehmen wir zum Beispiel diese Funktion:
Wenn ich es so nennen
Dann wird der code ausgeführt, wie dies
Obwohl, wirft den Punkt, was passiert, wenn der Kennung name-clash. Im klassischen call-by-name, ein Mechanismus namens " capture-Vermeidung substitution stattfindet, um zu vermeiden, name-clashes. In der Scala, aber umgesetzt wird dies in einer anderen Art und Weise mit dem gleichen Ergebnis -- Bezeichner-Namen innerhalb der parameter kann nicht Lesen "oder" Schatten-IDS in der Funktion.
Gibt es einige andere Punkte im Zusammenhang mit der call-by-name, die werde ich sprechen, der nach der Erläuterung der beiden anderen.
0-stelligkeit von Funktionen: () => Typ
Die syntax
() => Type
steht für den Typ einerFunction0
. Das ist eine Funktion die keine Parameter hat und etwas zurückgibt. Dies ist äquivalent zu sagen, das die Methode aufruftsize()
-- es braucht keine Parameter und gibt eine Zahl zurück.Interessant ist jedoch, dass diese syntax ist sehr ähnlich der syntax für eine anonymes funktionsliteral, die die Ursache für einige Verwirrung. Zum Beispiel,
ist ein anonymes funktionsliteral der stelligkeit 0, deren Typ ist
So könnten wir schreiben:
Ist es wichtig, nicht zu verwirren, der Typ mit dem Wert, aber.
Unit => Typ
Dies ist eigentlich nur ein
Function1
, dessen Erster parameter ist vom TypUnit
. Andere Möglichkeiten, es zu schreiben, wäre(Unit) => Type
oderFunction1[Unit, Type]
. Die Sache ist die... es ist unwahrscheinlich, dass jemals das, was man will. DieUnit
Typ Hauptzweck ist, der angibt, ein Wert ist nicht daran interessiert, so wenig Sinn erhalten Wert.Betrachten, zum Beispiel,
Was könnte man evtl. tun, mit
x
? Es kann nur ein einzelner Wert, so braucht man nicht erhalten. Eine mögliche Anwendung wäre Verkettung von Funktionen zurückgebenUnit
:Weil
andThen
ist nur definiert, aufFunction1
, und den Funktionen, die wir sind, die die Verkettung der RückkehrUnit
wir hatten, Sie zu definieren, als der TypFunction1[Unit, Unit]
zu können Kette.Quellen der Verwirrung
Die erste Quelle der Verwirrung ist, denken die ähnlichkeit zwischen dem Text und literal existiert für 0-arheit-Funktionen besteht auch für call-by-name. In anderen Worten, denken, dass, weil
ist ein literal für
() => Unit
, dannwäre ein literal für
=> Unit
. Es ist nicht. Das ist ein code-block, nicht wörtlich.Eine weitere Quelle der Verwirrung ist, dass
Unit
Typ Wert geschrieben()
, die aussieht wie eine 0-arheit-parameter-Liste (ist es aber nicht).Naja, die Frage nicht Fragen
case ... =>
, so wollte ich nicht erwähnen. Traurig, aber wahr. 🙂C. Sobral könnten Sie bitte erklären, " Das ist ein block von code, nicht wörtlich." Teil. Also, was ist der genaue Unterschied zwischen beiden?
Ein "literal" ist ein Wert (der ganzzahlige
1
, den Charakter'a'
die Zeichenfolge"abc"
oder die Funktion() => println("here")
für einige Beispiele). Es kann als argument übergeben wird, gespeichert in der Variablen, etc. Ein "code-block" ist eine syntaktische Abgrenzung von Anweisungen-es ist nicht ein Wert, es können sich nicht übergeben, oder so etwas.Das ist der gleiche Unterschied wie
(Unit) => Type
vs() => Type
-- das erste ist einFunction1[Unit, Type]
, während der zweite ist einFunction0[Type]
.InformationsquelleAutor Daniel C. Sobral
Den
case
modifier implizitval
sich jedes argument an den Konstruktor übergeben. Daher (als jemand erwähnt) wenn Sie entfernencase
Sie können eine call-by-name-parameter. Der compiler könnte wahrscheinlich erlauben es trotzdem, aber es könnte die Leute überraschen, wenn es erstelltval callback
statt morphing inlazy val callback
.Beim Wechsel zu
callback: () => Unit
jetzt Ihren Fall dauert nur eine Funktion eher als ein call-by-name-parameter. Offensichtlich ist die Funktion gespeichert werden können, inval callback
so gibt es kein problem.Der einfachste Weg, um zu bekommen, was Sie wollen (
Scheduled(40, println("x") )
bei call-by-name-parameter wird verwendet, um eine lambda) ist wahrscheinlich zu überspringencase
und explizit erstellen, dieapply
dass konnte man nicht in Erster Linie:Im Einsatz:
Wie können Sie überschreiben eine Fall-Klasse Standard-Methode anwenden? stackoverflow.com/questions/2660975/...
Objekt ClassName { def apply(...): ... = ... }
Vier Jahre später, und ich merke, dass die Antwort, die ich nur ausgewählt, beantwortet die Frage im Titel, nicht die, die ich eigentlich hatte (das dieser Antwort).
InformationsquelleAutor Ben Jackson
In der Frage, die Sie simulieren möchten SetTimeOut-Funktion in JavaScript. Basierend auf früheren Antworten, Schreibe ich folgenden code:
In REPL, wir bekommen so etwas wie dieses:
Unserer simulation verhält sich nicht genau das gleiche wie SetTimeOut, weil unsere simulation ist-blocking-Funktion, aber SetTimeOut ist nicht-blockierend.
InformationsquelleAutor Jeff Xu