Ich habe Scala-Funktionen gelesen (Teil einer weiteren Tour durch Scala ). In diesem Beitrag erklärte er:
Methoden und Funktionen sind nicht dasselbe
Aber er hat nichts darüber erklärt. Was wollte er sagen?
Ich habe Scala-Funktionen gelesen (Teil einer weiteren Tour durch Scala ). In diesem Beitrag erklärte er:
Methoden und Funktionen sind nicht dasselbe
Aber er hat nichts darüber erklärt. Was wollte er sagen?
Antworten:
Jim hat dies in seinem Blog-Beitrag ziemlich ausführlich behandelt , aber ich poste hier ein Briefing als Referenz.
Lassen Sie uns zunächst sehen, was uns die Scala-Spezifikation sagt. Kapitel 3 (Typen) enthält Informationen zu Funktionstypen (3.2.9) und Methodentypen (3.3.1). Kapitel 4 (Grunddeklarationen) spricht von Werterklärungen und Definitionen (4.1), Variablendeklarationen und Definitionen (4.2) und Funktionsdeklarationen und Definitionen (4.6). Kapitel 6 (Ausdrücke) spricht von anonymen Funktionen (6.23) und Methodenwerten (6.7). Seltsamerweise wird am 3.2.9 einmal von Funktionswerten gesprochen, und nirgendwo anders.
Ein Funktionstyp ist (ungefähr) ein Typ der Form (T1, ..., Tn) => U , die eine Abkürzung für das Merkmal
FunctionN
in der Standardbibliothek ist. Anonyme Funktionen und Methodenwerte haben Funktionstypen, und Funktionstypen können als Teil von Wert-, Variablen- und Funktionsdeklarationen und -definitionen verwendet werden. Tatsächlich kann es Teil eines Methodentyps sein.Ein Methodentyp ist ein Nichtwerttyp . Das heißt, es gibt keinen Wert - kein Objekt, keine Instanz - mit einem Methodentyp. Wie oben erwähnt, hat ein Methodenwert tatsächlich einen Funktionstyp . Ein Methodentyp ist eine
def
Deklaration - alles über adef
außer seinem Körper.Wertdeklarationen und -definitionen sowie Variablendeklarationen und -definitionen sind
val
undvar
Deklarationen, einschließlich Typ und Wert , die jeweils Funktionstyp- und anonyme Funktionen oder Methodenwerte sein können . Beachten Sie, dass diese (Methodenwerte) in der JVM mit den von Java als "Methoden" bezeichneten Methoden implementiert werden.Eine Funktionsdeklaration ist eine
def
Deklaration, einschließlich Typ und Text . Der Typteil ist der Methodentyp, und der Körper ist ein Ausdruck oder ein Block . Dies wird auch in der JVM mit den von Java als "Methoden" bezeichneten Methoden implementiert.Schließlich ist eine anonyme Funktion eine Instanz eines Funktionstyps (dh eine Instanz des Merkmals
FunctionN
), und ein Methodenwert ist dasselbe! Der Unterschied besteht darin, dass ein Methodenwert aus Methoden erstellt wird, entweder durch Nachfixieren eines Unterstrichs (m _
ist ein Methodenwert, der der "Funktionsdeklaration" (def
) entsprichtm
) oder durch einen Prozess namens eta-extension , der einer automatischen Umwandlung von method ähnelt Funktionieren.Das sagen die Spezifikationen, also lassen Sie mich dies vorwegnehmen: Wir verwenden diese Terminologie nicht! Dies führt zu einer zu großen Verwechslung zwischen der sogenannten "Funktionsdeklaration" , die Teil des Programms ist (Kapitel 4 - Grunddeklarationen), und der "anonymen Funktion" , die ein Ausdruck ist, und dem "Funktionstyp" , dh Nun, ein Typ - eine Eigenschaft.
Die folgende Terminologie, die von erfahrenen Scala-Programmierern verwendet wird, ändert sich gegenüber der Terminologie der Spezifikation: Anstatt Funktionsdeklaration zu sagen, sagen wir Methode . Oder sogar Methodendeklaration. Darüber hinaus stellen wir fest, dass Wertdeklarationen und Variablendeklarationen auch Methoden für praktische Zwecke sind.
Angesichts der obigen Änderung der Terminologie finden Sie hier eine praktische Erklärung der Unterscheidung.
Eine Funktion ist ein Objekt , das eines der umfasst
FunctionX
Merkmale, wie zum BeispielFunction0
,Function1
,Function2
usw. Es könnte sein , einschließlichPartialFunction
als auch, was sich eigentlichFunction1
.Sehen wir uns die Typensignatur für eines dieser Merkmale an:
Dieses Merkmal hat eine abstrakte Methode (es gibt auch einige konkrete Methoden):
Und das sagt uns alles, was es darüber zu wissen gibt. Eine Funktion hat eine
apply
Methode, die N Parameter vom Typ T1 , T2 , ..., TN empfängt und etwas vom Typ zurückgibtR
. Es ist eine Gegenvariante der empfangenen Parameter und eine Co-Variante des Ergebnisses.Diese Varianz bedeutet, dass a
Function1[Seq[T], String]
ein Subtyp von istFunction1[List[T], AnyRef]
. Ein Subtyp zu sein bedeutet, dass er anstelle davon verwendet werden kann. Man kann leicht erkennen,f(List(1, 2, 3))
dass einerAnyRef
der beiden oben genannten Typen funktionieren würde , wenn ich anrufen und einen Rücken erwarten würde.Was ist nun die Ähnlichkeit einer Methode und einer Funktion? Nun, wenn
f
es sich um eine Funktion undm
eine lokale Methode im Bereich handelt, können beide folgendermaßen aufgerufen werden:Diese Aufrufe sind tatsächlich unterschiedlich, da der erste nur ein syntaktischer Zucker ist. Scala erweitert es auf:
Was natürlich ein Methodenaufruf für ein Objekt ist
f
. Funktionen haben auch andere syntaktische Zucker im Vorteil: Funktionsliterale (zwei davon tatsächlich) und(T1, T2) => R
Typensignaturen. Beispielsweise:Eine weitere Ähnlichkeit zwischen einer Methode und einer Funktion besteht darin, dass die erstere leicht in die letztere umgewandelt werden kann:
Scala wird erweitert , dass unter der Annahme ,
m
Typ ist(List[Int])AnyRef
in (Scala 2.7):In Scala 2.8 wird tatsächlich eine
AbstractFunction1
Klasse verwendet, um die Klassengröße zu reduzieren.Beachten Sie, dass man nicht umgekehrt konvertieren kann - von einer Funktion zu einer Methode.
Methoden haben jedoch einen großen Vorteil (zwei - sie können etwas schneller sein): Sie können Typparameter empfangen . Während
f
oben beispielsweise notwendigerweise der Typ desList
Empfangs angegeben werden kann (List[Int]
im Beispiel),m
kann es beispielsweise parametrisiert werden:Ich denke, das deckt so ziemlich alles ab, aber ich werde dies gerne mit Antworten auf alle verbleibenden Fragen ergänzen.
quelle
val f = m
durch den Compiler zitierenval f = new AnyRef with Function1[List[Int], AnyRef] { def apply(x$1: List[Int]) = this.m(x$1) }
, sollten Sie darauf hinweisen, dass sich dasthis
Innere derapply
Methode nicht auf dasAnyRef
Objekt bezieht , sondern auf das Objekt, in dessen Methode dasval f = m _
ausgewertet wird ( sozusagen das Äußere)this
), dathis
zu den Werten gehört, die vom Abschluss erfasst werden (wie z. B.return
wie unten angegeben).Ein großer praktischer Unterschied zwischen einer Methode und einer Funktion ist, was
return
bedeutet.return
kehrt immer nur von einer Methode zurück. Beispielsweise:Die Rückgabe von einer in einer Methode definierten Funktion führt zu einer nicht lokalen Rückgabe:
Während die Rückkehr von einer lokalen Methode nur von dieser Methode zurückkehrt.
quelle
for (a <- List(1, 2, 3)) { return ... }
? Das wird zu einer Schließung entzuckert.return
einen Wert von der Funktion und eine Form vonescape
oderbreak
odercontinue
von Methoden zurückgegeben.Programmierung in Scala Second Edition. Martin Odersky - Lex Löffel - Bill Venners
quelle
Angenommen, Sie haben eine Liste
Definieren Sie eine Methode
Definieren Sie eine Funktion
Methode, die das Argument akzeptiert
Funktion mit val definieren
Das Argument für die Funktion ist optional
Das Argument zur Methode ist obligatorisch
Überprüfen Sie das folgende Lernprogramm , in dem erläutert wird, wie andere Unterschiede anhand von Beispielen wie anderen Beispielen für diff mit Methode Vs-Funktion übergeben werden. Verwenden Sie die Funktion als Variablen und erstellen Sie eine Funktion, die die Funktion zurückgibt
quelle
Funktionen unterstützen keine Parameterstandards. Methoden tun. Beim Konvertieren von einer Methode in eine Funktion gehen die Standardeinstellungen der Parameter verloren. (Scala 2.8.1)
quelle
Hier gibt es einen schönen Artikel , aus dem die meisten meiner Beschreibungen stammen. Nur ein kurzer Vergleich der Funktionen und Methoden in Bezug auf mein Verständnis. Ich hoffe es hilft:
Funktionen : Sie sind im Grunde ein Objekt. Genauer gesagt sind Funktionen Objekte mit einer Apply-Methode. Daher sind sie aufgrund ihres Overheads etwas langsamer als Methoden. Es ähnelt statischen Methoden in dem Sinne, dass sie unabhängig von einem aufzurufenden Objekt sind. Ein einfaches Beispiel für eine Funktion ist wie folgt:
Die obige Zeile ist nichts anderes als das Zuweisen eines Objekts zu einem anderen wie object1 = object2. Tatsächlich ist das Objekt2 in unserem Beispiel eine anonyme Funktion und die linke Seite erhält aus diesem Grund den Typ eines Objekts. Daher ist jetzt f1 ein Objekt (Funktion). Die anonyme Funktion ist tatsächlich eine Instanz von Function1 [Int, Int], dh eine Funktion mit 1 Parameter vom Typ Int und einem Rückgabewert vom Typ Int. Wenn Sie f1 ohne die Argumente aufrufen, erhalten Sie die Signatur der anonymen Funktion (Int => Int =).
Methoden : Sie sind keine Objekte, sondern einer Instanz einer Klasse zugeordnet, dh einem Objekt. Genau das gleiche wie die Methode in Java oder die Member-Funktionen in c ++ (wie Raffi Khatchadourian in einem Kommentar zu dieser Frage hervorhob ) usw. Ein einfaches Beispiel für eine Methode ist wie folgt:
Die obige Zeile ist keine einfache Wertzuweisung, sondern eine Definition einer Methode. Wenn Sie diese Methode mit dem Wert 2 wie in der zweiten Zeile aufrufen, wird das x durch 2 ersetzt und das Ergebnis wird berechnet und Sie erhalten 4 als Ausgabe. Hier erhalten Sie eine Fehlermeldung, wenn Sie einfach m1 schreiben, da es sich um eine Methode handelt und den Eingabewert benötigt. Mit _ können Sie einer Funktion wie unten eine Methode zuweisen:
quelle
Hier ist ein großartiger Beitrag von Rob Norris, der den Unterschied erklärt, hier ist ein TL; DR
mit folgender Definition:
Kurz gesagt ( Auszug aus dem Blog ):
Wenn wir eine Methode definieren, sehen wir, dass wir sie nicht einer zuweisen können
val
.Beachten Sie auch die Art von
add1
, die nicht normal aussieht; Sie können keine Variable vom Typ deklarieren(n: Int)Int
. Methoden sind keine Werte.Durch Hinzufügen des Postfix-Operators für die η-Erweiterung (η wird „eta“ ausgesprochen) können wir die Methode jedoch in einen Funktionswert umwandeln. Beachten Sie die Art von
f
.Dies
_
hat zur Folge, dass Folgendes ausgeführt wird: Wir erstellen eineFunction1
Instanz, die an unsere Methode delegiert.quelle
In Scala 2.13 können Methoden im Gegensatz zu Funktionen Methoden übernehmen / zurückgeben
Diese Einschränkungen werden jedoch in dotty (Scala 3) durch die polymorphen Funktionstypen # 4672 aufgehoben. Beispielsweise aktiviert dotty Version 0.23.0-RC1 die folgende Syntax
Geben Sie Parameter ein
Implizite Parameter ( Kontextparameter )
Abhängige Typen
Weitere Beispiele finden Sie unter tests / run / polymorphic-functions.scala
quelle
In der Praxis muss ein Scala-Programmierer nur die folgenden drei Regeln kennen, um Funktionen und Methoden ordnungsgemäß verwenden zu können:
def
und Funktionsliterale definierte Methoden=>
sind Funktionen. Es ist in Seite 143, Kapitel 8 des Buches Programmieren in Scala, 4. Auflage, definiert.someNumber.foreach(println)
Nach vier Ausgaben von Programming in Scala ist es immer noch ein Problem für die Menschen, die beiden wichtigen Konzepte zu unterscheiden: Funktion und Funktionswert, da nicht alle Ausgaben eine klare Erklärung geben. Die Sprachspezifikation ist zu kompliziert. Ich fand die obigen Regeln einfach und genau.
quelle