Différence entre la méthode et la fonction dans Scala

j'ai lu Scala Fonctions (une partie de un Autre tour de la Scala ). Dans ce billet, il a déclaré:

les méthodes et les fonctions ne sont pas la même chose

mais il n'a rien expliqué. Qu'était-il en train de dire?

221
demandé sur Peter Mortensen 2010-03-27 15:06:16

6 réponses

Jim a obtenu CE à peu près beaucoup couvert dans son billet de blog , mais je poste un briefing ici pour référence.

voyons D'abord ce que la spécification Scala nous dit. Chapitre 3 (types) nous parler de types de fonction (3.2.9) et types de méthode (3.3.1). Le chapitre 4 (déclarations de base) parle de déclaration de valeur et définitions (4.1), Variable Déclaration et définitions (4.2) et fonctions déclarations et définitions (4.6). Le chapitre 6 (expressions) parle de fonctions anonymes (6.23) et valeurs de méthode (6.7). Curieusement, les valeurs de fonction sont parlées d'une fois sur 3.2.9, et nulle part ailleurs.

A Type de fonction est (approximativement) un type de la forme (T1, ..., Tn) = > U , qui est un raccourci pour le trait FunctionN dans la bibliothèque standard. fonctions anonymes et valeurs de méthode ont des types de fonctions, et les types de fonctions peuvent être utilisés comme partie de la valeur, des déclarations de variables et de fonctions et des définitions. En fait, il peut faire partie d'un type de méthode.

Un Méthode de Type est un non-type de la valeur . Cela signifie qu'il y est non valeur - aucun objet, aucune instance n' - avec un type de méthode. Comme mentionné ci-dessus, une valeur de la méthode a en fait un Type de fonction . Un type de méthode est une def déclaration - tout au sujet d'un def sauf son corps.

déclarations de valeur et définitions et déclarations variables et définitions sont val et var , y compris les déclarations type et valeur - qui peuvent être, respectivement, Type de fonction et fonctions anonymes ou valeurs de méthode . Notez que, sur la JVM, ces (valeurs de méthode) sont implémentées avec ce que Java appelle des "méthodes".

A déclaration de fonction est une déclaration def , incluant type et 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'un La valeur de la méthode est créée à partir des méthodes, soit par postfixation d'un underscore ( m _ est une valeur de la méthode correspondant à la "déclaration de la fonction" ( def ) m ), ou par un procédé appelé eta-expansion , qui est comme un moulage automatique de méthode à fonction.

C'est ce que disent les spécifications, alors permettez-moi de mettre cela en avant: nous n'utilisons pas cette terminologie! il conduit à trop de confusion entre soi - disant " déclaration de fonction " , qui fait partie du programme (chapitre 4 -- déclarations de base) et " fonction anonyme , qui est une expression, et "type de fonction" , qui est, bien un type -- un trait.

la terminologie ci-dessous, et utilisé par les programmeurs expérimentés de Scala, fait un changement de la terminologie de la spécification: au lieu de dire fonction déclaration , nous disons méthode . Ou même déclaration de méthode. En outre, nous notons que déclarations de valeur et déclarations variables sont également des méthodes à des fins pratiques.

ainsi, compte tenu du changement de terminologie ci-dessus, voici une explication pratique de la distinction.

a fonction est un objet qui inclut l'un des traits FunctionX , tels que Function0 , Function1 , Function2 , etc. Il pourrait inclure PartialFunction ainsi, qui s'étend réellement Function1 .

voyons la signature type pour l'un de ces traits:

trait Function2[-T1, -T2, +R] extends AnyRef

ce trait a une méthode abstraite (il a aussi quelques méthodes concrètes):

def apply(v1: T1, v2: T2): R

Et qui nous disent tous qu'il y a à savoir sujet. Une fonction a une méthode apply qui reçoit n paramètres des types T1 , T2 ,..., TN , et renvoie à quelque chose de type R . Il est contre-variante sur les paramètres qu'il reçoit, et co-variante sur le résultat.

cette variance signifie qu'un Function1[Seq[T], String] est un sous-type de Function1[List[T], AnyRef] . Étant un sous-type moyen il peut être utilisé à la place de il. On peut facilement voir que si je vais appeler f(List(1, 2, 3)) et attendre un AnyRef de retour, l'un ou l'autre 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 et m est une méthode locale à la portée, alors les deux peuvent être appelés comme ceci:

val o1 = f(List(1, 2, 3))
val o2 = m(List(1, 2, 3))

ces appels sont en fait différent, parce que le premier est juste un sucre syntaxique. Scala l'étend à:

val o1 = f.apply(List(1, 2, 3))

Qui, bien sûr, est un appel de méthode sur l'objet f . Les fonctions ont également d'autres sucres syntaxiques à leur avantage: fonction littérales (deux d'entre eux, en fait) et (T1, T2) => R type signatures. Par exemple:

val f = (l: List[Int]) => l mkString ""
val g: (AnyVal) => String = {
  case i: Int => "Int"
  case d: Double => "Double"
  case o => "Other"
}

une autre similitude entre une méthode et une fonction est que la première peut être facilement convertie en ce dernier:

val f = m _

Scala va étendre que , en supposant que m type est (List[Int])AnyRef dans (Scala 2.7):

val f = new AnyRef with Function1[List[Int], AnyRef] {
  def apply(x: List[Int]) = this.m(x)
}

sur Scala 2.8, il utilise en fait une classe AbstractFunction1 pour réduire la taille des classes.

remarquez que l'un ne peut pas convertir l'autre -- d'une fonction à une méthode.

Méthodes, cependant, ont un grand avantage (enfin, deux, ils peuvent être légèrement plus rapide): ils peuvent recevoir paramètres de type . Par exemple, alors que f ci-dessus peut nécessairement spécifier le type de List qu'il reçoit ( List[Int] dans l'exemple), m peut paramétrer:

def m[T](l: List[T]): String = l mkString ""

je pense que cela couvre à peu près tout, mais je serai heureux de compléter cela avec des réponses à toutes les questions qui peuvent rester.

211
répondu Daniel C. Sobral 2014-06-02 12:53:03

une grande différence pratique entre une méthode et une fonction est ce que return signifie. return ne revient jamais d'une méthode. Par exemple:

scala> val f = () => { return "test" }
<console>:4: error: return outside method definition
       val f = () => { return "test" }
                       ^

de Retour d'une fonction définie dans une méthode d'un non-local de retour:

scala> def f: String = {                 
     |    val g = () => { return "test" }
     | g()                               
     | "not this"
     | }
f: String

scala> f
res4: String = test

alors que le retour d'une méthode locale ne retourne que de cette méthode.

scala> def f2: String = {         
     | def g(): String = { return "test" }
     | g()
     | "is this"
     | }
f2: String

scala> f2
res5: String = is this
64
répondu Ben Lings 2010-03-27 15:53:57

fonction Une fonction peut être appelée avec une liste d'arguments pour produire un résultat. Une fonction a une liste de paramètres, un corps, et un type de résultat. Les fonctions qui sont membres d'une classe, trait, ou objet singleton sont appelé méthodes . Fonctions définies à l'intérieur d'autres fonctions sont appelées les fonctions locales. Les fonctions avec le type de résultat D'Unité s'appellent des procédures. Les fonctions anonymes dans le code source sont appelées la fonction de littéraux. Au moment de l'exécution, les fonctions littérales sont instanciées dans des objets appelés les valeurs de la fonction.

Programming in Scala Second Edition. Martin Odersky-Lex Spoon-Bill Venners

33
répondu jamlhet 2014-07-01 20:35:47

Disons que vous avez une Liste

scala> val x =List.range(10,20)
x: List[Int] = List(10, 11, 12, 13, 14, 15, 16, 17, 18, 19)

Définir une Méthode

scala> def m1(i:Int)=i+2
m1: (i: Int)Int

Définir une Fonction

scala> (i:Int)=>i+2
res0: Int => Int = <function1>

scala> x.map((x)=>x+2)
res2: List[Int] = List(12, 13, 14, 15, 16, 17, 18, 19, 20, 21)

Argument D'Acceptation De Méthode

scala> m1(2)
res3: Int = 4

la Définition de la Fonction avec le val

scala> val p =(i:Int)=>i+2
p: Int => Int = <function1>

Argument à la fonction est facultatif

 scala> p(2)
    res4: Int = 4

scala> p
res5: Int => Int = <function1>

Argument à la méthode est obligatoire

scala> m1
<console>:9: error: missing arguments for method m1;
follow this method with `_' if you want to treat it as a partially applied function

Vérifier le après tutoriel qui explique passer d'autres différences avec des exemples comme autre exemple de diff avec la méthode Vs fonction, en utilisant la fonction comme Variables, la création de la fonction qui renvoie la fonction

27
répondu anish 2015-01-14 15:08:27
Les fonctions

ne prennent pas en charge les paramètres par défaut. Les méthodes le font. La conversion d'une méthode à une fonction perd le paramètre par défaut. (Scala 2.8.1)

11
répondu eptx 2011-05-03 22:36:50

il y a un bel article ici d'où la plupart de mes descriptions sont prises. Juste une brève comparaison des fonctions et des méthodes en ce qui concerne ma compréhension. Espérons que cela aide:

fonctions : Ils sont essentiellement un objet. Plus précisément, les fonctions sont des objets avec une méthode d'application; par conséquent, ils sont un peu plus lents que les méthodes en raison de leur overhead. Il est similaire aux méthodes statiques dans le sens où ils sont indépendants d'un objet à être invoqué. Un exemple simple d'une fonction est comme ci-dessous:

val f1 = (x: Int) => x + x
f1(2)  // 4

la ligne ci-dessus n'est rien sauf assigner un objet à un autre comme object1 = object2. En fait le objet2 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 valeur de retour de type Int. Appeler f1 sans les arguments nous donnera la signature de la fonction anonyme (Int = > Int = )

méthodes : Il ne s'agit pas d'objets mais d'une instance d'une classe,c'est-à-dire d'un objet. Exactement le même que la méthode en java ou les fonctions de membre en c++ (comme Raffi Khatchadourian a souligné dans un commentaire à cette question ) et etc. Simple exemple d'une méthode est comme ci-dessous:

def m1(x: Int) = x + x
m1(2)  // 4

la ligne ci-dessus n'est pas une simple assignation 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 parce que c'est la méthode et que vous avez besoin de la valeur d'entrée. En utilisant _ vous pouvez assigner une méthode à une fonction comme bellow:

val f2 = m1 _  // Int => Int = <function1>
3
répondu Mehran 2018-02-23 14:38:27