2010-03-27 50 views
209

leí Scala Functions (parte de Otro tour de Scala). En ese puesto, afirmó:diferencia entre el método y la función de Scala

Métodos y funciones no son la misma cosa

Pero no explicó nada al respecto. ¿Qué estaba tratando de decir?

+1

http://jim-mcbeath.blogspot.com/2009/05/scala-functions-vs-methods.html –

+2

creo que se puede obtener algo de [Cuál es la diferencia entre un método y una función] (http://stackoverflow.com/questions/155609/what-is-the-difference-between-a-method-and-a-function) – jinglining

+0

A Pregunta de seguimiento con buenas respuestas: [Funciones vs métodos en Scala] (http://stackoverflow.com/questions/4839537/functions-vs-methods-in-scala) –

Respuesta

60

Una gran diferencia práctica entre un método y una función es lo que significa return. return solo regresa de un método. Por ejemplo:

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

Volviendo de una función definida en un método hace un retorno no local:

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

scala> f 
res4: String = test 

Considerando regresar de un método local solamente regresa de ese método.

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

scala> f2 
res5: String = is this 
+7

Esto se debe a que el cierre se captura mediante el cierre. –

+9

Wow, puedo ver que esto lleva a un código realmente confuso ... – Phob

+4

No puedo pensar en una sola vez en la que me gustaría 'devolver' de una función al alcance no local. De hecho, puedo ver que es un serio problema de seguridad si una función puede decidir que quiere ir más atrás en la pila. Se siente algo así como longjmp, solo que es más fácil equivocarse accidentalmente. Sin embargo, me he dado cuenta de que Scalac no me permitirá volver de las funciones. ¿Eso significa que esta abominación ha sido eliminada del lenguaje? – root

202

Jim ha conseguido este más o menos cubierto de his blog post, pero estoy publicar una rueda de aquí por referencia.

Primero, veamos qué nos dicen las especificaciones de Scala. El Capítulo 3 (tipos) nos habla de Tipos de función (3.2.9) y Tipos de métodos (3.3.1). El capítulo 4 (declaraciones básicas) habla de Declaración de valores y definiciones (4.1), Declaración de variables y definiciones (4.2) y Funciones Declaraciones y definiciones (4.6). El capítulo 6 (expresiones) habla de Funciones anónimas (6.23) y Valores de método (6.7). Curiosamente, los valores de función se hablan una vez en 3.2.9, y en ningún otro lado.

A Tipo Función es (más o menos) de un tipo de forma (T1, ..., Tn) => T, que es una abreviatura para el rasgo FunctionN en la biblioteca estándar. Funciones anónimas y Los valores del método tienen tipos de funciones, y los tipos de funciones se pueden usar como parte de declaraciones y definiciones de valores, variables y funciones. De hecho, puede ser parte de un tipo de método.

A Tipo Método es una no valor de tipo de. Eso significa que hay no valor - sin objeto, sin instancia - con un tipo de método. Como se mencionó anteriormente, un Método Valor en realidad tiene un Tipo de función. Un tipo de método es una declaración def, todo sobre un def excepto su cuerpo.

Valor declaraciones y definiciones y Declaraciones de variables y definiciones son val y var declaraciones, incluyendo tanto tipo y valor - que puede ser, respectivamente, Tipo Función y funciones anónimas o Método valores. Tenga en cuenta que, en la JVM, estos (valores de método) se implementan con lo que Java llama "métodos".

Una Declaración Función es una declaración def, incluyendo tipo y cuerpo. La parte de tipo es el Tipo de método, y el cuerpo es una expresión o un bloque. Esto también se implementa en la JVM con lo que Java llama "métodos".

Por último, un Anónimo Función es una instancia de un tipo de función (es decir, una instancia del rasgo FunctionN), y un método de Valores la misma cosa! La distinción es que un Método de valor se crea a partir de métodos, ya sea por postfijación de un guión bajo (m _ es un valor de método correspondiente a la "declaración de función" (def) m), o por un proceso llamado eta-expansion, que es como un lanzamiento automático del método a la función.

Eso es lo que dicen las especificaciones, así que permítanme poner esto por adelantado: ¡no usamos esa terminología! Conduce a demasiada confusión entre la llamada "declaración de función", que es una parte del programa (capítulo 4 - declaraciones básicas) y "función anónima", que es una función de expresión, y " escriba ", que es, bueno, un tipo, un rasgo.

La siguiente terminología, y utilizado por los programadores experimentados Scala, hace un cambio de la terminología de la especificación: en lugar de decir la declaración función, decimos método. O incluso declaración de método. Además, observamos que declaraciones de valores y declaraciones de variables también son métodos para fines prácticos.

Por lo tanto, dado el cambio de terminología anterior, aquí hay una explicación práctica de la distinción.

A función es un objeto que incluye uno de los FunctionX rasgos, tales como Function0, Function1, Function2, etc. Se podría incluyendo PartialFunction, así, que en realidad se extiende Function1.

Veamos la firma tipo para uno de estos rasgos:

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

Este rasgo tiene un método abstracto (que tiene unos métodos concretos así):

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

Y que nos dicen todo lo que hay que saber al respecto. Una funcióntiene un método apply que recibe N parámetros de tipos T1, T2, ..., TN , y devuelve algo de tipo R. Es contravariante en los parámetros que recibe, y covariante en el resultado.

Esa variación significa que un Function1[Seq[T], String] es un subtipo de Function1[List[T], AnyRef]. Al ser un subtipo, significa que se puede usar en lugar de. Uno puede ver fácilmente que si voy a llamar al f(List(1, 2, 3)) y espero un AnyRef, cualquiera de los dos tipos anteriores funcionaría.

Ahora, ¿cuál es la similitud de un método y una función? Bueno, si f es una función y m es un método local para el alcance, entonces ambos pueden llamarse así:

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

Estas llamadas son realmente diferentes, porque el primero es sólo un azúcar sintáctico. Scala se expande a:

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

cual, por supuesto, es una llamada a un método en el objeto f. Las funciones también tienen otros azúcares sintácticos a su favor: los literales de función (dos de ellos, en realidad) y las firmas de tipo (T1, T2) => R. Por ejemplo:

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

Otra similitud entre un método y una función es que el primero se puede convertir fácilmente en el último:

val f = m _ 

Scala se expandirá que, suponiendo m tipo es (List[Int])AnyRef en (Scala 2,7):

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

En Scala 2.8, en realidad se utiliza un cl AbstractFunction1 culo para reducir el tamaño de las clases.

Observe que no se puede convertir a la inversa, de una función a un método.

Los métodos, sin embargo, tienen una gran ventaja (bueno, dos, pueden ser un poco más rápidos): pueden recibir los parámetros de tipo .Por ejemplo, mientras f anterior se puede especificar necesariamente el tipo de List que recibe (List[Int] en el ejemplo), puede parametrizar m que:

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

creo que esto prácticamente cubre todo, pero voy a ser feliz para complementar esto con respuestas a cualquier pregunta que pueda permanecer.

+22

Esta explicación es muy clara. Bien hecho. Desafortunadamente tanto el libro de Odersky/Venners/Spoon como la especificación de Scala usan las palabras "función" y "método" de manera intercambiable. (Son más propensos a decir "función" donde "método" sería más claro, pero a veces sucede de la otra manera, por ejemplo, la sección 6.7 de la especificación, que abarca la conversión de métodos a funciones, se denomina "Valores de método". .) Creo que el uso suelto de estas palabras ha generado mucha confusión cuando las personas intentan aprender el idioma. –

+4

@Seth Lo sé, lo sé - PinS fue el libro que me enseñó Scala. Aprendí mejor de la manera difícil, es decir, paulp me enderezó. –

+3

¡Gran explicación!Tengo una cosa que añadir: cuando cita la expansión de 'val f = m' por el compilador como' val f = new AnyRef con Function1 [List [Int], AnyRef] { def apply (x $ 1: List [Int ]) = this.m (x $ 1) } 'debe señalar que el' this' dentro del método 'apply' no se refiere al objeto' AnyRef', sino al objeto en cuyo método 'val f = m _' se evalúa (el _outer_ 'this', por así decirlo), ya que' this' está entre los valores que son capturados por el cierre (como por ejemplo 'return' como se señala a continuación). –

11

Las funciones no son compatibles con los parámetros predeterminados. Los métodos lo hacen. La conversión de un método a una función pierde los parámetros predeterminados. (Scala 2.8.1)

+4

¿Hay alguna razón para esto? – corazza

26

Digamos que usted tiene una lista de

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

definir un método

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

definir una función

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) 

Método aceptar el argumento

scala> m1(2) 
res3: Int = 4 

Definición de Función con val

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

argumento de la función es opcional

scala> p(2) 
    res4: Int = 4 

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

argumento de método es obligatorio

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 

Compruebe lo siguiente Tutorial que explica paso otras diferencias con ejemplos como otro ejemplo de diff con el Método Vs Función, Usando la función como Variables, creando la función n que la función

28

función Una función devuelve puede ser invocado con una lista de argumentos para producir un resultado . Una función tiene una lista de parámetros, un cuerpo y un tipo de resultado. Las funciones que son miembros de un objeto de clase, rasgo o singleton son llamados métodos. Las funciones definidas dentro de otras funciones se llaman funciones locales . Las funciones con el tipo de resultado de la Unidad se llaman procedimientos. Las funciones anónimas en el código fuente se llaman literales de funciones. En tiempo de ejecución, los literales de funciones se instancian en objetos llamados valores de función .

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

+0

Una función puede pertenecer a una clase como def o como val/var. Solo los def son métodos. –

1

hay un buen artículo here del que se toman la mayoría de mis descripciones. Solo una breve comparación de funciones y métodos con respecto a mi comprensión. Espero que ayude:

Funciones: Básicamente son un objeto. Más precisamente, las funciones son objetos con un método de aplicación; Por lo tanto, son un poco más lentos que los métodos debido a su sobrecarga. Es similar a los métodos estáticos en el sentido de que son independientes de un objeto que se invocará. Un ejemplo sencillo de una función es igual abajo:

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

La línea anterior es nada excepto la asignación de un objeto a otro como object1 = object2. En realidad, el objeto2 en nuestro ejemplo es una función anónima y el lado izquierdo recibe el tipo de objeto debido a eso. Por lo tanto, ahora f1 es un objeto (Función). La función anónima es en realidad una instancia de la Función 1 [Int, Int] que significa una función con 1 parámetro de tipo Int y valor de retorno de tipo Int. Llamando F1 sin los argumentos nos dará la firma de la función anónima (Int => Int =)

Métodos:. No son objetos, sino asignados a una instancia de una clase, es decir, un objeto. Exactamente lo mismo que el método en las funciones de Java o miembro en C++ (como Raffi Khatchadourian señaló en un comentario a this question) y etc. Un ejemplo sencillo de un método es igual abajo:

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

La línea anterior no es una simple asignación de valores pero una definición de un método. Cuando invoque este método con el valor 2 como la segunda línea, la x se sustituye por 2 y se calculará el resultado y obtendrá 4 como salida. Aquí obtendrá un error si simplemente escribe m1 porque es un método y necesita el valor de entrada. Mediante el uso de _ se puede asignar un método para una función como abajo:

val f2 = m1 _ // Int => Int = <function1> 
Cuestiones relacionadas