class Person(val name:String,var age:Int )
def person = new Person("Kumar",12)
person.age = 20
println(person.age)
Essas linhas de saída de código 12
, mesmo que tenham person.age=20
sido executadas com sucesso. Descobri que isso acontece porque usei def in def person = new Person("Kumar",12)
. Se eu usar var ou val, a saída é 20
. Entendo que o padrão é val in scala. Este:
def age = 30
age = 45
... fornece um erro de compilação porque é um valor por padrão. Por que o primeiro conjunto de linhas acima não funciona corretamente e também não gera erros?
val
pode ser alterado, mas o objeto referido por uma val não pode. Aval
não é uma constante.List
comofinal
, mas pode modificar seu conteúdo.Eu começaria pela distinção que existe em Scala entre def , val e var .
def - define um rótulo imutável para o conteúdo do lado direito que é avaliado preguiçosamente - avalie pelo nome.
val - define um rótulo imutável para o conteúdo do lado direito que é avidamente / imediatamente avaliado - avaliado por valor.
var - define uma variável mutável , inicialmente definida como o conteúdo avaliado do lado direito.
Exemplo, def
Exemplo, val
Exemplo, var
De acordo com o acima, as etiquetas def e val não podem ser reatribuídas e, em caso de tentativa, será gerado um erro como o abaixo:
Quando a classe é definida como:
e instanciado com:
um rótulo imutável é criado para essa instância específica de Person (ou seja, 'personA'). Sempre que o campo mutável 'idade' precisar ser modificado, essa tentativa falha:
como esperado, 'idade' faz parte de um rótulo não mutável. A maneira correta de trabalhar nisso consiste em usar uma variável mutável, como no exemplo a seguir:
Como claro, a partir da referência da variável mutável (ou seja, 'personB'), é possível modificar o campo mutável da classe 'age'.
Eu ainda enfatizaria o fato de que tudo deriva da diferença acima mencionada, que deve estar clara em mente para qualquer programador Scala.
fonte
personA
et al. parece desligado. Se a modificação doage
membro funciona ou não, é independente de você usardef personA
ouvar personB
. A diferença é que, nodef personA
caso de você estar modificando aPerson
instância-retornada de sua primeira avaliação depersonA
. Essa instância é modificada, mas não é o que é retornado quando você avalia novamentepersonA
. Em vez disso, na segunda vez em quepersonA.age
você efetivamente está fazendonew Person("Tim",25).age
.Com
você está definindo uma variável function / lazy que sempre retorna uma nova instância Person com o nome "Kumar" e 12 anos. Isso é totalmente válido e o compilador não tem motivos para reclamar. Chamar person.age retornará a idade dessa instância Person recém-criada, que é sempre 12.
Ao escrever
você atribui um novo valor à propriedade age na classe Person, que é válida desde que a idade seja declarada como
var
. O compilador reclamará se você tentar reatribuirperson
com um novo objeto Person comofonte
Para fornecer outra perspectiva, "def" no Scala significa algo que será avaliado toda vez que for usado, enquanto val é algo que é avaliado imediatamente e apenas uma vez . Aqui, a expressão
def person = new Person("Kumar",12)
implica que sempre que usarmos "pessoa", receberemos umanew Person("Kumar",12)
ligação. Portanto, é natural que os dois "person.age" não estejam relacionados.É assim que entendo Scala (provavelmente de uma maneira mais "funcional"). Não tenho certeza se
é realmente o que Scala pretende dizer. Eu realmente não gosto de pensar assim, pelo menos ...
fonte
Como o Kintaro já diz, person é um método (por causa de def) e sempre retorna uma nova instância de Person. Como você descobriu, funcionaria se você alterasse o método para um var ou val:
Outra possibilidade seria:
No entanto,
person.age=20
seu código é permitido, pois você recupera umaPerson
instância doperson
método e, nessa instância, você pode alterar o valor de avar
. O problema é que, depois dessa linha, você não tem mais referência a essa instância (como cada chamada paraperson
produzirá uma nova instância).Isso não é nada de especial, você teria exatamente o mesmo comportamento em Java:
fonte
Vamos pegar o seguinte:
e reescreva-o com código equivalente
Veja,
def
é um método. Ele será executado sempre que for chamado e sempre que retornar (a)new Person("Kumar", 12)
. E não há erro na "atribuição" porque não é realmente uma tarefa, mas apenas uma chamada para oage_=
método (fornecido porvar
).fonte