Hola que Int => Booleansignifica Creo que la sintaxis definida esdef foo(bar: Baz): Bin = expr
Ziu
@Ziu eso significa que la función 'par' recibe un Int como argumento y devuelve un Booleano como un tipo de valor. Entonces puede llamar 'even (3)' que se evalúa como booleano 'false'
Denys Lobur
@DenysLobur gracias por tu respuesta! ¿Alguna referencia sobre esta sintaxis?
Ziu
@Ziu Básicamente lo descubrí en el curso Coursera de Odersky : coursera.org/learn/progfun1 . Cuando lo termines, entenderás lo que significa 'Tipo => Tipo'
Denys Lobur
Respuestas:
325
El método def evenevalúa la llamada y crea una nueva función cada vez (nueva instancia de Function1).
def even:Int=>Boolean= _ %2==0
even eq even
//Boolean = falseval even:Int=>Boolean= _ %2==0
even eq even
//Boolean = true
Con defusted puede obtener una nueva función en cada llamada:
val test:()=>Int={val r = util.Random.nextInt
()=> r
}
test()// Int = -1049057402
test()// Int = -1049057402 - same resultdef test:()=>Int={val r = util.Random.nextInt
()=> r
}
test()// Int = -240885810
test()// Int = -1002157461 - new result
valevalúa cuando se define, def- cuando se llama:
scala>val even:Int=>Boolean=???
scala.NotImplementedError: an implementation is missing
scala>def even:Int=>Boolean=???
even:Int=>Boolean
scala> even
scala.NotImplementedError: an implementation is missing
Tenga en cuenta que hay una tercera opción: lazy val.
Se evalúa cuando se llama por primera vez:
scala>lazyval even:Int=>Boolean=???
even:Int=>Boolean=<lazy>
scala> even
scala.NotImplementedError: an implementation is missing
Pero devuelve el mismo resultado (en este caso, la misma instancia de FunctionN) cada vez:
lazyval even:Int=>Boolean= _ %2==0
even eq even
//Boolean = truelazyval test:()=>Int={val r = util.Random.nextInt
()=> r
}
test()// Int = -1068569869
test()// Int = -1068569869 - same result
Actuación
val evalúa cuando se define.
defevalúa en cada llamada, por lo que el rendimiento podría ser peor que valpara varias llamadas. Obtendrá el mismo rendimiento con una sola llamada. Y sin llamadas no obtendrá gastos generales def, por lo que puede definirlo incluso si no lo usará en algunas ramas.
Con un lazy valobtendrá una evaluación perezosa: puede definirlo incluso si no lo usará en algunas ramas, y evalúa una vez o nunca, pero obtendrá un poco de sobrecarga por el bloqueo de doble verificación en cada acceso a su lazy val.
Como señaló @SargeBorsch, podría definir el método, y esta es la opción más rápida:
def even(i:Int):Boolean= i %2==0
Pero si necesita una función (no un método) para la composición de funciones o para un filter(even)compilador de funciones de orden superior (como ) generará una función a partir de su método cada vez que la use como función, por lo que el rendimiento podría ser ligeramente peor que con val.
¿Podría compararlos con respecto al rendimiento? ¿No es importante evaluar la función cada vez que evense llama?
Amir Karimi
2
defse puede usar para definir un método, y esta es la opción más rápida. @ A.Karimi
Nombre para mostrar
2
Para la diversión: en 2.12, even eq even.
som-snytt
¿Existe un concepto de funciones en línea como en c ++? Vengo del mundo c ++, así que perdón por mi ignorancia.
animageofmine
2
El compilador @animageofmine Scala puede intentar incorporar métodos. Hay un @inlineatributo para esto. Pero no puede incluir funciones en línea porque la llamada de función es una llamada al applymétodo virtual de un objeto de función. JVM podría desvirtualizar e incorporar tales llamadas en algunas situaciones, pero no en general.
senia
24
Considera esto:
scala>def even:(Int=>Boolean)={
println("def");(x => x %2==0)}
even:Int=>Boolean
scala>val even2:(Int=>Boolean)={
println("val");(x => x %2==0)}val//gets printed while declaration. line-4
even2:Int=>Boolean=<function1>
scala> even(1)def
res9:Boolean=false
scala> even2(1)
res10:Boolean=false
¿Ves la diferencia? En breve:
def : por cada llamada a even, vuelve a llamar al cuerpo del evenmétodo. Pero con even2ie val , la función se inicializa solo una vez durante la declaración (y, por lo tanto, se imprime valen la línea 4 y nunca más) y se usa la misma salida cada vez que se accede. Por ejemplo, intente hacer esto:
scala>import scala.util.Randomimport scala.util.Random
scala>val x ={Random.nextInt }
x:Int=-1307706866
scala> x
res0:Int=-1307706866
scala> x
res1:Int=-1307706866
Cuando xse inicializa, el valor devuelto por Random.nextIntse establece como el valor final de x. La próxima vez que xse use nuevamente, siempre devolverá el mismo valor.
También puedes inicializar perezosamente x. es decir, la primera vez que se usa se inicializa y no mientras se declara. Por ejemplo:
scala>lazyval y ={Random.nextInt }
y:Int=<lazy>
scala> y
res4:Int=323930673
scala> y
res5:Int=323930673
Creo que su explicación puede implicar algo que no tiene intención. Intenta llamar even2dos veces, una con 1y otra con 2. Obtendrá diferentes respuestas en cada llamada. Entonces, aunque printlnno se ejecuta en llamadas posteriores, no obtiene el mismo resultado de diferentes llamadas a even2. En cuanto a por qué printlnno se ejecuta nuevamente, esa es una pregunta diferente.
melston
1
eso es realmente muy interesante Es como en el caso de val, es decir, even2, el val se evalúa a un valor parametrizado. entonces sí, con un val usted la evaluación de la función, su valor. El println no es parte del valor evaluado. Es parte de la evaluación pero no el valor evaluado. El truco aquí es que el valor evaluado es en realidad un valor parametarizado, que depende de alguna entrada. cosa inteligente
MaatDeamon
1
@melston exactamente! eso es lo que entendí, entonces, ¿por qué no se vuelve a ejecutar println mientras cambia la salida?
aur
1
@aur lo que devuelve even2 es en realidad una función (la expresión entre paréntesis al final de la definición de even2). Esa función se llama realmente con el parámetro que pasa a even2 cada vez que lo invoca.
melston 01 de
5
Mira esto:
var x =2// using var as I need to change it to 3 laterval sq = x*x // evaluates right now
x =3// no effect! sq is already evaluated
println(sq)
¡Sorprendentemente, esto imprimirá 4 y no 9! val (incluso var) se evalúa inmediatamente y se asigna.
Ahora cambie val a def .. ¡imprimirá 9! Def es una llamada a función ... se evaluará cada vez que se llame.
val es decir, "sq" es, por definición Scala, es fijo. Se evalúa justo en el momento de la declaración, no se puede cambiar más tarde. En otros ejemplos, donde even2 también es val, pero se declaró con la firma de la función, es decir, "(Int => Boolean)", por lo que no es de tipo Int. Es una función y su valor se establece siguiendo la expresión
{
println("val");(x => x %2==0)}
Según la propiedad Scala val, no puede asignar otra función a even2, la misma regla que sq.
¿Por qué llamar a la función eval2 val no imprime "val" una y otra vez?
Código de origen:
val even2:(Int=>Boolean)={
println("val");(x => x %2==0)}
Sabemos que en Scala la última declaración del tipo de expresión anterior (dentro de {..}) es en realidad volver al lado izquierdo. Por lo tanto, termina configurando even2 en la función "x => x% 2 == 0", que coincide con el tipo que declaró para el tipo even2 val, es decir (Int => Boolean), por lo que el compilador está contento. Ahora even2 solo apunta a la función "(x => x% 2 == 0)" (no cualquier otra instrucción anterior, es decir, println ("val") etc. Invocar event2 con diferentes parámetros invocará realmente "(x => x% 2) == 0) "código, ya que solo eso se guarda con event2.
Ejecutar una definición como def x = eno evaluará la expresión e. En su lugar, e se evalúa cada vez que se invoca x.
Alternativamente, Scala ofrece una definición de valor
val x = e, que evalúa el lado derecho como parte de la evaluación de la definición. Si x se usa posteriormente, se reemplaza inmediatamente por el valor precalculado de e, de modo que la expresión no necesita ser evaluada nuevamente.
Además, Val es una evaluación por valor. Lo que significa que la expresión del lado derecho se evalúa durante la definición. Donde Def es por evaluación de nombre. No evaluará hasta que se use.
Además de las respuestas útiles anteriores, mis hallazgos son:
def test1:Int=>Int={
x => x
}--test1: test1[]=>Int=>Intdef test2():Int=>Int={
x => x+1}--test2: test2[]()=>Int=>Intdef test3():Int=4--test3: test3[]()=>Int
Lo anterior muestra que "def" es un método (con parámetros de argumento cero) que devuelve otra función "Int => Int" cuando se invoca.
Con una pregunta tan antigua, y con tantas respuestas ya enviadas, a menudo es útil explicar cómo su respuesta difiere o se agrega a la información proporcionada en las respuestas existentes.
Int => Boolean
significa Creo que la sintaxis definida esdef foo(bar: Baz): Bin = expr
Respuestas:
El método
def even
evalúa la llamada y crea una nueva función cada vez (nueva instancia deFunction1
).Con
def
usted puede obtener una nueva función en cada llamada:val
evalúa cuando se define,def
- cuando se llama:Tenga en cuenta que hay una tercera opción:
lazy val
.Se evalúa cuando se llama por primera vez:
Pero devuelve el mismo resultado (en este caso, la misma instancia de
FunctionN
) cada vez:Actuación
val
evalúa cuando se define.def
evalúa en cada llamada, por lo que el rendimiento podría ser peor queval
para varias llamadas. Obtendrá el mismo rendimiento con una sola llamada. Y sin llamadas no obtendrá gastos generalesdef
, por lo que puede definirlo incluso si no lo usará en algunas ramas.Con un
lazy val
obtendrá una evaluación perezosa: puede definirlo incluso si no lo usará en algunas ramas, y evalúa una vez o nunca, pero obtendrá un poco de sobrecarga por el bloqueo de doble verificación en cada acceso a sulazy val
.Como señaló @SargeBorsch, podría definir el método, y esta es la opción más rápida:
Pero si necesita una función (no un método) para la composición de funciones o para un
filter(even)
compilador de funciones de orden superior (como ) generará una función a partir de su método cada vez que la use como función, por lo que el rendimiento podría ser ligeramente peor que conval
.fuente
even
se llama?def
se puede usar para definir un método, y esta es la opción más rápida. @ A.Karimieven eq even
.@inline
atributo para esto. Pero no puede incluir funciones en línea porque la llamada de función es una llamada alapply
método virtual de un objeto de función. JVM podría desvirtualizar e incorporar tales llamadas en algunas situaciones, pero no en general.Considera esto:
¿Ves la diferencia? En breve:
def : por cada llamada a
even
, vuelve a llamar al cuerpo deleven
método. Pero coneven2
ie val , la función se inicializa solo una vez durante la declaración (y, por lo tanto, se imprimeval
en la línea 4 y nunca más) y se usa la misma salida cada vez que se accede. Por ejemplo, intente hacer esto:Cuando
x
se inicializa, el valor devuelto porRandom.nextInt
se establece como el valor final dex
. La próxima vez quex
se use nuevamente, siempre devolverá el mismo valor.También puedes inicializar perezosamente
x
. es decir, la primera vez que se usa se inicializa y no mientras se declara. Por ejemplo:fuente
even2
dos veces, una con1
y otra con2
. Obtendrá diferentes respuestas en cada llamada. Entonces, aunqueprintln
no se ejecuta en llamadas posteriores, no obtiene el mismo resultado de diferentes llamadas aeven2
. En cuanto a por quéprintln
no se ejecuta nuevamente, esa es una pregunta diferente.Mira esto:
¡Sorprendentemente, esto imprimirá 4 y no 9! val (incluso var) se evalúa inmediatamente y se asigna.
Ahora cambie val a def .. ¡imprimirá 9! Def es una llamada a función ... se evaluará cada vez que se llame.
fuente
val es decir, "sq" es, por definición Scala, es fijo. Se evalúa justo en el momento de la declaración, no se puede cambiar más tarde. En otros ejemplos, donde even2 también es val, pero se declaró con la firma de la función, es decir, "(Int => Boolean)", por lo que no es de tipo Int. Es una función y su valor se establece siguiendo la expresión
Según la propiedad Scala val, no puede asignar otra función a even2, la misma regla que sq.
¿Por qué llamar a la función eval2 val no imprime "val" una y otra vez?
Código de origen:
Sabemos que en Scala la última declaración del tipo de expresión anterior (dentro de {..}) es en realidad volver al lado izquierdo. Por lo tanto, termina configurando even2 en la función "x => x% 2 == 0", que coincide con el tipo que declaró para el tipo even2 val, es decir (Int => Boolean), por lo que el compilador está contento. Ahora even2 solo apunta a la función "(x => x% 2 == 0)" (no cualquier otra instrucción anterior, es decir, println ("val") etc. Invocar event2 con diferentes parámetros invocará realmente "(x => x% 2) == 0) "código, ya que solo eso se guarda con event2.
Solo para aclarar esto más, la siguiente es una versión diferente del código.
Lo que sucederá ? aquí vemos "interior fn final" impreso una y otra vez, cuando llamas a even2 ().
fuente
Ejecutar una definición como
def x = e
no evaluará la expresión e. En su lugar, e se evalúa cada vez que se invoca x.Alternativamente, Scala ofrece una definición de valor
val x = e
, que evalúa el lado derecho como parte de la evaluación de la definición. Si x se usa posteriormente, se reemplaza inmediatamente por el valor precalculado de e, de modo que la expresión no necesita ser evaluada nuevamente.fuente
Además, Val es una evaluación por valor. Lo que significa que la expresión del lado derecho se evalúa durante la definición. Donde Def es por evaluación de nombre. No evaluará hasta que se use.
fuente
Además de las respuestas útiles anteriores, mis hallazgos son:
Lo anterior muestra que "def" es un método (con parámetros de argumento cero) que devuelve otra función "Int => Int" cuando se invoca.
La conversión de métodos a funciones se explica aquí: https://tpolecat.github.io/2014/06/09/methods-functions.html
fuente
En REPL,
def significa
call-by-name
, evaluado bajo demandaval significa
call-by-value
, evaluado durante la inicializaciónfuente