scala - for - eta programming language
¿Cuál es la diferencia entre def foo={} y def foo()={} en Scala? (4)
Teniendo en cuenta los siguientes constructos para definir una función en Scala, ¿puede explicar cuál es la diferencia y cuáles serán sus implicaciones?
def foo = {}
vs.
def foo() = {}
Actualizar
Gracias por las rápidas respuestas. Estos son geniales La única pregunta que me queda es:
Si omito el paréntesis, ¿todavía hay una manera de pasar la función? Esto es lo que obtengo en el repl:
scala> def foo = {}
foo: Unit
scala> def baz() = {}
baz: ()Unit
scala> def test(arg: () => Unit) = { arg }
test: (arg: () => Unit)() => Unit
scala> test(foo)
<console>:10: error: type mismatch;
found : Unit
required: () => Unit
test(foo)
^
scala> test(baz)
res1: () => Unit = <function0>
Actualización 2012-09-14
Aquí hay algunas preguntas similares que noté:
- Diferencia entre función con paréntesis y sin
- Métodos Scala sin argumentos
Déjame copiar mi respuesta que publiqué en una pregunta duplicada :
Se puede definir un método Scala de 0-arity con o sin paréntesis ()
. Esto se usa para indicarle al usuario que el método tiene algún tipo de efecto secundario (como imprimir para eliminar o destruir datos), a diferencia del que no tiene, que luego se puede implementar como val
.
Ver Programación en Scala :
Tales métodos sin parámetros son bastante comunes en Scala. Por el contrario, los métodos definidos con paréntesis vacíos, como def height (): Int, se llaman métodos empty-paren. La convención recomendada es usar un método sin parámetros siempre que no haya parámetros y el método accede al estado mutable solo leyendo los campos del objeto que lo contiene (en particular, no cambia el estado mutable).
Esta convención apoya el principio de acceso uniforme [...]
Para resumir, se alienta el estilo en Scala para definir métodos que no toman parámetros y no tienen efectos secundarios como métodos sin parámetros, es decir, dejando fuera el paréntesis vacío. Por otro lado, nunca debe definir un método que tenga efectos secundarios sin paréntesis, porque las invocaciones de ese método se verían como una selección de campo.
Para responder a su segunda pregunta, simplemente agregue un _
:
scala> def foo = println("foo!")
foo: Unit
scala> def test(arg: () => Unit) = { arg }
test: (arg: () => Unit)() => Unit
scala> test(foo _)
res10: () => Unit = <function0>
scala> test(foo _)()
foo!
scala>
Si incluye los paréntesis en la definición, puede omitirlos opcionalmente cuando llame al método. Si los omite en la definición, no puede usarlos cuando llama al método.
scala> def foo() {}
foo: ()Unit
scala> def bar {}
bar: Unit
scala> foo
scala> bar()
<console>:12: error: Unit does not take parameters
bar()
^
Además, puede hacer algo similar con sus funciones de orden superior:
scala> def baz(f: () => Unit) {}
baz: (f: () => Unit)Unit
scala> def bat(f: => Unit) {}
bat: (f: => Unit)Unit
scala> baz(foo)
scala> baz(bar)
<console>:13: error: type mismatch;
found : Unit
required: () => Unit
baz(bar)
^
scala> bat(foo)
scala> bat(bar) // both ok
Aquí baz
solo tomará foo()
y no bar
. De qué sirve esto, no lo sé. Pero muestra que los tipos son distintos.
Yo recomendaría siempre comenzar la definición con una función como:
def bar {}
y solo en los casos, cuando se lo fuerce, para cambiarlo a:
def bar() {}
Motivo: Consideremos estas 2 funciones desde un punto de posible uso. Cómo pueden ser infundidos Y dónde se pueden pasar.
Yo no llamaría esto una función en absoluto:
def bar {}
Se puede invocar como:
bar
pero no como una función:
bar()
Podemos usar esta barra cuando definimos una función de orden superior con un parámetro de llamada por nombre:
def bat(f: => Unit) {
f //you must not use (), it will fail f()
}
Deberíamos recordar, que => Unit
- ni siquiera es una función. No puede trabajar con un procesador como si fuera una función en la medida en que no puede elegir tratarlo como valor de Función para almacenarlo o transferirlo. Solo puede activar evaluaciones de la expresión de argumento real (cualquier número de ellas). Scala: función de paso como bloque de código entre llaves
Una función, definida con ()
tiene un alcance mayor para el uso. Se puede usar exactamente, en el mismo contexto, como bar
:
def foo() = {}
//invokation:
foo
//or as a function:
foo()
Se puede pasar a una función con un parámetro de llamada por nombre:
bat(foo)
Además, si definimos una función de orden superior, no acepta un pamámetro de llamada por nombre, sino una función real:
def baz(f: () => Unit) {}
También podemos pasar foo
al baz
:
baz(foo)
Como podemos ver, las funciones estándar como foo
tienen un mayor alcance para el uso. Pero usando una función definida sin ()
más la definición de funciones de orden superior, que acepten el parámetro call-by-name, usemos una sintaxis más clara.
Si no intenta archivar un código mejor y más legible, o si necesita capacidad para pasar su fragmento de código tanto a la función definida con un parámetro de llamada por nombre como a una función definida con una función real, defina su funciona como estándar uno:
def foo() {}
Si prefiere escribir un código más claro y legible, Y su función no tiene efectos secundarios, defina una función como:
def bar {}
ADEMÁS intente definir su función de orden superior para aceptar un parámetro de llamada por nombre, pero no una función. Solo cuando sea forzado, solo en este caso use la opción anterior.