Oi, o que Int => Booleansignifica? Eu acho que a sintaxe de definição édef foo(bar: Baz): Bin = expr
Ziu
@Ziu significa que a função 'even' recebe um Int como argumento e retorna um Booleano como um tipo de valor. Assim, você pode chamar 'even (3)', que é avaliado como booleano 'false'
Denys Lobur
@ DenysLobur obrigado pela sua resposta! Alguma referência sobre esta sintaxe?
Ziu
@Ziu Basicamente, descobri isso no curso Cursera de Odersky - coursera.org/learn/progfun1 . Quando você terminar, você entenderá o que significa 'Type => Type' #
Denys Lobur 08/10
Respostas:
325
O método def evenavalia na chamada e cria novas funções sempre (nova instância de Function1).
def even:Int=>Boolean= _ %2==0
even eq even
//Boolean = falseval even:Int=>Boolean= _ %2==0
even eq even
//Boolean = true
Com defvocê pode obter novas funções em cada chamada:
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
valavalia quando definido, def- quando chamado:
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
Observe que há uma terceira opção: lazy val.
Ele avalia quando chamado pela primeira vez:
scala>lazyval even:Int=>Boolean=???
even:Int=>Boolean=<lazy>
scala> even
scala.NotImplementedError: an implementation is missing
Mas retorna o mesmo resultado (neste caso, a mesma instância de FunctionN) sempre:
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
atuação
val avalia quando definido.
defavalia em todas as chamadas, portanto, o desempenho pode ser pior do que valem várias chamadas. Você obterá o mesmo desempenho com uma única chamada. E sem chamadas, você não terá custos indiretos def, portanto, você pode defini-la mesmo que não a utilize em algumas ramificações.
Com um, lazy valvocê obtém uma avaliação preguiçosa: você pode defini-lo mesmo que não o use em alguns ramos, e ele avalia uma vez ou nunca, mas você terá um pouco de sobrecarga com o bloqueio de verificação dupla em todos os acessos ao seu lazy val.
Como o @SargeBorsch observou, você pode definir o método, e esta é a opção mais rápida:
def even(i:Int):Boolean= i %2==0
Mas se você precisar de uma função (não método) para a composição da função ou para o filter(even)compilador de funções de ordem superior (como ), gerará uma função do seu método toda vez que você a estiver usando como função, portanto, o desempenho poderá ser um pouco pior do que com val.
Você poderia compará-los em relação ao desempenho? Não é importante avaliar a função cada vez que evené chamada.
Amir Karimi
2
defpode ser usado para definir um método, e essa é a opção mais rápida. @ A.Karimi
Nome de exibição
2
Por diversão: em 2.12 even eq even,.
som-snytt
Existe um conceito de funções embutidas como no c ++? Eu estou vindo do mundo c ++, então perdoe minha ignorância.
Animageofmine
2
@animageofmine O compilador Scala pode tentar métodos embutidos. Há @inlineatributo para isso. Mas não pode integrar funções porque a chamada de função é uma chamada ao applymétodo virtual de um objeto de função. A JVM pode destirtualizar e alinhar essas chamadas em algumas situações, mas não em geral.
senia
24
Considere isto:
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
Você vê a diferença? Em resumo:
def : Para cada chamada para even, ele chama o corpo do evenmétodo novamente. Mas com even2ie val , a função é inicializada apenas uma vez durante a declaração (e, portanto, imprime valna linha 4 e nunca mais) e a mesma saída é usada cada vez que é acessada. Por exemplo, tente fazer isso:
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
Quando xé inicializado, o valor retornado por Random.nextInté definido como o valor final de x. A próxima vez que xfor usada novamente, sempre retornará o mesmo valor.
Você também pode inicializar preguiçosamente x. ou seja, na primeira vez em que é usado, é inicializado e não durante a declaração. Por exemplo:
scala>lazyval y ={Random.nextInt }
y:Int=<lazy>
scala> y
res4:Int=323930673
scala> y
res5:Int=323930673
Acho que sua explicação pode implicar algo que você não pretende. Tente ligar even2duas vezes, uma vez com 1e uma vez com 2. Você receberá respostas diferentes em cada chamada. Portanto, enquanto o printlnnão for executado em chamadas subsequentes, você não obtém o mesmo resultado de chamadas diferentes para even2. Quanto ao motivo de printlnnão ser executado novamente, essa é uma pergunta diferente.
17249 melston
1
isso é realmente muito interessante. É como no caso de val, ou seja, even2, a val é avaliada para um valor parametrizado. então sim com um val você a avaliação da função, seu valor. O println não faz parte do valor avaliado. Faz parte da avaliação, mas não o valor avaliado. O truque aqui é que o valor avaliado é realmente um valor parametarizado, que depende de alguma entrada. coisa inteligente
MaatDeamon
1
@melston exatamente! foi isso que eu entendi. Por que o println não é executado novamente enquanto a saída é alterada?
aur
1
@aur o que é retornado por even2 é na verdade uma função (a expressão entre parênteses no final da definição de even2). Essa função é realmente chamada com o parâmetro que você passa para even2 toda vez que a invoca.
melston
5
Veja isso:
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)
Surpreendentemente, isso imprimirá 4 e não 9! val (even var) é avaliado imediatamente e atribuído.
Agora mude val para def .. ele imprimirá 9! Def é uma chamada de função. Ele avalia cada vez que é chamado.
val ie "sq" é definido pela definição de Scala. É avaliado no momento da declaração, você não pode alterar mais tarde. Em outros exemplos, onde even2 também val, mas declarou com a assinatura da função ou seja "(Int => Boolean)", portanto não é do tipo Int. É uma função e seu valor é definido pela seguinte expressão
{
println("val");(x => x %2==0)}
Conforme a propriedade Scala val, você não pode atribuir outra função para even2, mesma regra que sq.
Por que a função eval2 val não está imprimindo "val" repetidamente?
Código Orig:
val even2:(Int=>Boolean)={
println("val");(x => x %2==0)}
Sabemos que, em Scala, a última declaração do tipo de expressão acima (dentro de {..}) é realmente retornar ao lado esquerdo. Então você acaba configurando even2 para a função "x => x% 2 == 0", que corresponde ao tipo que você declarou para o tipo even2 val, isto é (Int => Boolean), para que o compilador fique feliz. Agora, even2 apenas aponta para a função "(x => x% 2 == 0)" (nenhuma outra declaração antes, por exemplo, println ("val")) etc. A chamada de event2 com parâmetros diferentes na verdade chama "(x => x% 2 == 0) ", pois somente isso é salvo com o evento2.
A execução de uma definição como def x = enão avaliará a expressão e. Em vez disso, é avaliado sempre que x é chamado.
Como alternativa, Scala oferece uma definição de valor
val x = e, que avalia o lado direito como parte da avaliação da definição. Se x for usado posteriormente, será imediatamente substituído pelo valor pré-calculado de e, para que a expressão não precise ser avaliada novamente.
Além disso, Val é uma avaliação por valor. O que significa que a expressão do lado direito é avaliada durante a definição. Onde Def é por avaliação de nome. Não avaliará até que seja usado.
Além das respostas úteis acima, minhas descobertas são:
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
O exemplo acima mostra que “def” é um método (com zero parâmetros de argumento) que retorna outra função "Int => Int" quando invocada.
Com uma pergunta tão antiga e com tantas respostas já enviadas, muitas vezes é útil explicar como sua resposta difere ou adiciona às informações fornecidas nas respostas existentes.
Int => Boolean
significa? Eu acho que a sintaxe de definição édef foo(bar: Baz): Bin = expr
Respostas:
O método
def even
avalia na chamada e cria novas funções sempre (nova instância deFunction1
).Com
def
você pode obter novas funções em cada chamada:val
avalia quando definido,def
- quando chamado:Observe que há uma terceira opção:
lazy val
.Ele avalia quando chamado pela primeira vez:
Mas retorna o mesmo resultado (neste caso, a mesma instância de
FunctionN
) sempre:atuação
val
avalia quando definido.def
avalia em todas as chamadas, portanto, o desempenho pode ser pior do queval
em várias chamadas. Você obterá o mesmo desempenho com uma única chamada. E sem chamadas, você não terá custos indiretosdef
, portanto, você pode defini-la mesmo que não a utilize em algumas ramificações.Com um,
lazy val
você obtém uma avaliação preguiçosa: você pode defini-lo mesmo que não o use em alguns ramos, e ele avalia uma vez ou nunca, mas você terá um pouco de sobrecarga com o bloqueio de verificação dupla em todos os acessos ao seulazy val
.Como o @SargeBorsch observou, você pode definir o método, e esta é a opção mais rápida:
Mas se você precisar de uma função (não método) para a composição da função ou para o
filter(even)
compilador de funções de ordem superior (como ), gerará uma função do seu método toda vez que você a estiver usando como função, portanto, o desempenho poderá ser um pouco pior do que comval
.fonte
even
é chamada.def
pode ser usado para definir um método, e essa é a opção mais rápida. @ A.Karimieven eq even
,.@inline
atributo para isso. Mas não pode integrar funções porque a chamada de função é uma chamada aoapply
método virtual de um objeto de função. A JVM pode destirtualizar e alinhar essas chamadas em algumas situações, mas não em geral.Considere isto:
Você vê a diferença? Em resumo:
def : Para cada chamada para
even
, ele chama o corpo doeven
método novamente. Mas comeven2
ie val , a função é inicializada apenas uma vez durante a declaração (e, portanto, imprimeval
na linha 4 e nunca mais) e a mesma saída é usada cada vez que é acessada. Por exemplo, tente fazer isso:Quando
x
é inicializado, o valor retornado porRandom.nextInt
é definido como o valor final dex
. A próxima vez quex
for usada novamente, sempre retornará o mesmo valor.Você também pode inicializar preguiçosamente
x
. ou seja, na primeira vez em que é usado, é inicializado e não durante a declaração. Por exemplo:fonte
even2
duas vezes, uma vez com1
e uma vez com2
. Você receberá respostas diferentes em cada chamada. Portanto, enquanto oprintln
não for executado em chamadas subsequentes, você não obtém o mesmo resultado de chamadas diferentes paraeven2
. Quanto ao motivo deprintln
não ser executado novamente, essa é uma pergunta diferente.Veja isso:
Surpreendentemente, isso imprimirá 4 e não 9! val (even var) é avaliado imediatamente e atribuído.
Agora mude val para def .. ele imprimirá 9! Def é uma chamada de função. Ele avalia cada vez que é chamado.
fonte
val ie "sq" é definido pela definição de Scala. É avaliado no momento da declaração, você não pode alterar mais tarde. Em outros exemplos, onde even2 também val, mas declarou com a assinatura da função ou seja "(Int => Boolean)", portanto não é do tipo Int. É uma função e seu valor é definido pela seguinte expressão
Conforme a propriedade Scala val, você não pode atribuir outra função para even2, mesma regra que sq.
Por que a função eval2 val não está imprimindo "val" repetidamente?
Código Orig:
Sabemos que, em Scala, a última declaração do tipo de expressão acima (dentro de {..}) é realmente retornar ao lado esquerdo. Então você acaba configurando even2 para a função "x => x% 2 == 0", que corresponde ao tipo que você declarou para o tipo even2 val, isto é (Int => Boolean), para que o compilador fique feliz. Agora, even2 apenas aponta para a função "(x => x% 2 == 0)" (nenhuma outra declaração antes, por exemplo, println ("val")) etc. A chamada de event2 com parâmetros diferentes na verdade chama "(x => x% 2 == 0) ", pois somente isso é salvo com o evento2.
Apenas para esclarecer isso, a seguir é apresentada uma versão diferente do código.
O que vai acontecer ? aqui vemos "inside final fn" impresso repetidamente, quando você chama even2 ().
fonte
A execução de uma definição como
def x = e
não avaliará a expressão e. Em vez disso, é avaliado sempre que x é chamado.Como alternativa, Scala oferece uma definição de valor
val x = e
, que avalia o lado direito como parte da avaliação da definição. Se x for usado posteriormente, será imediatamente substituído pelo valor pré-calculado de e, para que a expressão não precise ser avaliada novamente.fonte
Além disso, Val é uma avaliação por valor. O que significa que a expressão do lado direito é avaliada durante a definição. Onde Def é por avaliação de nome. Não avaliará até que seja usado.
fonte
Além das respostas úteis acima, minhas descobertas são:
O exemplo acima mostra que “def” é um método (com zero parâmetros de argumento) que retorna outra função "Int => Int" quando invocada.
A conversão de métodos em funções é bem explicada aqui: https://tpolecat.github.io/2014/06/09/methods-functions.html
fonte
No REPL,
def significa
call-by-name
, avaliado sob demandamédias val
call-by-value
, avaliadas durante a inicializaçãofonte