J'ai lu les fonctions Scala (partie d'une autre tournée de Scala ). Dans ce poste, il a déclaré:
Les méthodes et les fonctions ne sont pas la même chose
Mais il n'a rien expliqué à ce sujet. Qu'essayait-il de dire?
J'ai lu les fonctions Scala (partie d'une autre tournée de Scala ). Dans ce poste, il a déclaré:
Les méthodes et les fonctions ne sont pas la même chose
Mais il n'a rien expliqué à ce sujet. Qu'essayait-il de dire?
Réponses:
Jim a couvert cela à peu près dans son article de blog , mais je poste ici un briefing pour référence.
Voyons d'abord ce que la spécification Scala nous dit. Le chapitre 3 (types) nous parle des types de fonctions (3.2.9) et des types de méthodes (3.3.1). Le chapitre 4 (déclarations de base) parle de déclaration et définitions de valeur (4.1), de déclaration et définitions de variable (4.2) et de déclarations et définitions de fonctions (4.6). Le chapitre 6 (expressions) parle des fonctions anonymes (6.23) et des valeurs de méthode (6.7). Curieusement, les valeurs de fonction sont parlées une seule fois sur 3.2.9, et nulle part ailleurs.
Un type de fonction est (à peu près) un type de la forme (T1, ..., Tn) => U , qui est un raccourci pour le trait
FunctionN
dans la bibliothèque standard. Les fonctions anonymes et les valeurs de méthode ont des types de fonction, et les types de fonction peuvent être utilisés dans le cadre des déclarations et définitions de valeurs, de variables et de fonctions. En fait, elle peut faire partie d'un type de méthode.Un type de méthode est un type sans valeur . Cela signifie qu'il n'y a pas de valeur - pas d'objet, pas d'instance - avec un type de méthode. Comme mentionné ci-dessus, une valeur de méthode a en fait un type de fonction . Un type de méthode est une
def
déclaration - tout ce qui concerne adef
sauf son corps.Valeur Déclarations et définitions et déclarations variables et définitions sont
val
etvar
déclarations, y compris les types et la valeur - qui peut être, respectivement, le type de fonction et fonctions anonymes ou valeurs Méthode . Notez que, sur la JVM, ces (valeurs de méthode) sont implémentées avec ce que Java appelle des "méthodes".Une déclaration de fonction est une
def
déclaration, y compris le type et le corps . La partie type est le type de méthode et le corps est une expression ou un bloc . Ceci est également implémenté sur la JVM avec ce que Java appelle des "méthodes".Enfin, une fonction anonyme est une instance d'un type de fonction (c'est-à-dire une instance du trait
FunctionN
), et une valeur de méthode est la même chose! La distinction est qu'une valeur de méthode est créée à partir de méthodes, soit en post-fixant un trait de soulignement (m _
est une valeur de méthode correspondant à la "déclaration de fonction" (def
)m
), soit par un processus appelé eta-expansion , qui est comme une conversion automatique de la méthode Pour fonctionner.C'est ce que disent les spécifications, alors permettez-moi de dire ceci: nous n'utilisons pas cette terminologie! Cela conduit à trop de confusion entre ce que l'on appelle la "déclaration de fonction" , qui fait partie du programme (chapitre 4 - déclarations de base) et la "fonction anonyme" , qui est une expression, et le "type de fonction" , qui est, bien un type - un trait.
La terminologie ci-dessous, et utilisée par les programmeurs Scala expérimentés, fait un changement par rapport à la terminologie de la spécification: au lieu de dire la déclaration de fonction , nous disons méthode . Ou même la déclaration de méthode. De plus, nous notons que les déclarations de valeurs et les déclarations de variables sont également des méthodes à des fins pratiques.
Donc, étant donné le changement de terminologie ci-dessus, voici une explication pratique de la distinction.
Une fonction est un objet qui comprend l' un des
FunctionX
traits, tels queFunction0
,Function1
,Function2
, etc. Il peut être comprisPartialFunction
aussi bien, qui se prolonge en faitFunction1
.Voyons la signature de type pour l'un de ces traits:
Ce trait a une méthode abstraite (il a aussi quelques méthodes concrètes):
Et cela nous dit tout ce qu'il y a à savoir à ce sujet. Une fonction a une
apply
méthode qui reçoit N paramètres de types T1 , T2 , ..., TN et renvoie quelque chose de typeR
. Il est contra-variant sur les paramètres qu'il reçoit, et co-variant sur le résultat.Cette variance signifie que a
Function1[Seq[T], String]
est un sous-type deFunction1[List[T], AnyRef]
. Être un sous-type signifie qu'il peut être utilisé à sa place . On peut facilement voir que si je vais appelerf(List(1, 2, 3))
et m'attendre à unAnyRef
retour, l'un des deux types ci-dessus fonctionnerait.Maintenant, quelle est la similitude d'une méthode et d'une fonction? Eh bien, si
f
est une fonction etm
est une méthode locale à la portée, les deux peuvent être appelées comme ceci:Ces appels sont en fait différents, car le premier n'est qu'un sucre syntaxique. Scala l'étend à:
Ce qui, bien sûr, est un appel de méthode sur un objet
f
. Les fonctions ont également d'autres sucres syntaxiques à son avantage: les littéraux de fonction (deux d'entre eux, en fait) et(T1, T2) => R
les signatures de type. Par exemple:Une autre similitude entre une méthode et une fonction est que la première peut être facilement convertie en la seconde:
Scala développera cela , en supposant que le
m
type est(List[Int])AnyRef
dans (Scala 2.7):Sur Scala 2.8, il utilise en fait une
AbstractFunction1
classe pour réduire la taille des classes.Notez que l'on ne peut pas convertir l'inverse - d'une fonction à une méthode.
Les méthodes ont cependant un gros avantage (enfin, deux - elles peuvent être légèrement plus rapides): elles peuvent recevoir des paramètres de type . Par exemple, alors que
f
ci-dessus peut nécessairement spécifier le type deList
réception (List[Int]
dans l'exemple), ilm
peut le paramétrer:Je pense que cela couvre à peu près tout, mais je serai heureux de le compléter avec des réponses à toutes les questions qui pourraient rester.
la source
val f = m
par le compilateur,val f = new AnyRef with Function1[List[Int], AnyRef] { def apply(x$1: List[Int]) = this.m(x$1) }
vous devez souligner que l'this
intérieur de laapply
méthode ne fait pas référence à l'AnyRef
objet, mais à l'objet dans la méthode duquelval f = m _
est évalué (l' extérieurthis
, pour ainsi dire ), carthis
fait partie des valeurs capturées par la fermeture (comme par exemple,return
comme indiqué ci-dessous).Une grande différence pratique entre une méthode et une fonction est ce que
return
signifie.return
ne revient que d'une méthode. Par exemple:Le retour d'une fonction définie dans une méthode fait un retour non local:
Alors que le retour d'une méthode locale ne revient que de cette méthode.
la source
for (a <- List(1, 2, 3)) { return ... }
? Cela devient sans sucre jusqu'à la fermeture.return
renvoyé une valeur de la fonction, et une certaine forme deescape
oubreak
oucontinue
pour retourner des méthodes.Programmation dans Scala Second Edition. Martin Odersky - Lex Spoon - Bill Venners
la source
Disons que vous avez une liste
Définir une méthode
Définir une fonction
Méthode acceptant l'argument
Définition d'une fonction avec val
L'argument pour fonctionner est facultatif
L'argument de la méthode est obligatoire
Consultez le didacticiel suivant qui explique comment passer d'autres différences avec des exemples comme un autre exemple de diff avec la fonction Method Vs, utiliser la fonction comme variables, créer une fonction qui a renvoyé la fonction
la source
Les fonctions ne prennent pas en charge les valeurs par défaut des paramètres. Les méthodes le font. La conversion d'une méthode en fonction perd les valeurs par défaut des paramètres. (Scala 2.8.1)
la source
Il y a un bel article ici dont la plupart de mes descriptions sont tirées. Juste une courte comparaison des fonctions et méthodes concernant ma compréhension. J'espère que ça aide:
Fonctions : Ils sont fondamentalement un objet. Plus précisément, les fonctions sont des objets avec une méthode apply; Par conséquent, elles sont un peu plus lentes que les méthodes en raison de leur surcharge. Elle est similaire aux méthodes statiques dans le sens où elles sont indépendantes d'un objet à invoquer. Un exemple simple de fonction est comme ci-dessous:
La ligne ci-dessus n'est rien sauf l'affectation d'un objet à un autre comme object1 = object2. En fait, object2 dans notre exemple est une fonction anonyme et le côté gauche obtient le type d'un objet à cause de cela. Par conséquent, maintenant f1 est un objet (Fonction). La fonction anonyme est en fait une instance de Function1 [Int, Int] qui signifie une fonction avec 1 paramètre de type Int et une valeur de retour de type Int. L'appel de f1 sans les arguments nous donnera la signature de la fonction anonyme (Int => Int =)
Méthodes : Ce ne sont pas des objets mais assignés à une instance d'une classe, c'est-à-dire un objet. Exactement la même que la méthode en java ou les fonctions membres en c ++ (comme Raffi Khatchadourian l'a souligné dans un commentaire à cette question ) et etc. Un exemple simple de méthode est comme ci-dessous:
La ligne ci-dessus n'est pas une simple attribution de valeur mais une définition d'une méthode. Lorsque vous appelez cette méthode avec la valeur 2 comme la deuxième ligne, le x est remplacé par 2 et le résultat sera calculé et vous obtenez 4 en sortie. Ici, vous obtiendrez une erreur si vous écrivez simplement m1 car c'est une méthode et vous avez besoin de la valeur d'entrée. En utilisant _, vous pouvez affecter une méthode à une fonction comme ci-dessous:
la source
Voici un excellent article de Rob Norris qui explique la différence, voici un TL; DR
avec la définition suivante:
En bref ( extrait du blog ):
Lorsque nous définissons une méthode, nous voyons que nous ne pouvons pas l'affecter à a
val
.Notez également le type de
add1
, qui ne semble pas normal; vous ne pouvez pas déclarer une variable de type(n: Int)Int
. Les méthodes ne sont pas des valeurs.Cependant, en ajoutant l'opérateur de suffixe η-expansion (η est prononcé "eta"), nous pouvons transformer la méthode en une valeur de fonction. Notez le type de
f
.L'effet de
_
est d'effectuer l'équivalent de ce qui suit: nous construisons uneFunction1
instance qui délègue à notre méthode.la source
Dans Scala 2.13, contrairement aux fonctions, les méthodes peuvent prendre / retourner
Cependant, ces restrictions sont levées dans dotty (Scala 3) par les types de fonctions polymorphes # 4672 , par exemple, la version 0.23.0-RC1 de dotty active la syntaxe suivante
Paramètres de type
Paramètres implicites ( paramètres de contexte )
Types dépendants
Pour plus d'exemples, voir tests / run / polymorphic-functions.scala
la source
Pratiquement, un programmeur Scala a seulement besoin de connaître les trois règles suivantes pour utiliser correctement les fonctions et les méthodes:
def
et les littéraux de fonction définis par=>
sont des fonctions. Il est défini à la page 143, chapitre 8 du livre de programmation de Scala, 4e édition.someNumber.foreach(println)
Après quatre éditions de Programming in Scala, il est toujours difficile pour les gens de différencier les deux concepts importants: fonction et valeur de fonction car toutes les éditions ne donnent pas d'explication claire. La spécification du langage est trop compliquée. J'ai trouvé que les règles ci-dessus sont simples et précises.
la source