Uso de def, val y var en scala

class Person(val name:String,var age:Int ) def person = new Person("Kumar",12) person.age = 20 println(person.age) 

Estas líneas de código person.age=20 resultado 12 , aunque person.age=20 se ejecutó con éxito. Descubrí que esto sucede porque utilicé def in def person = new Person("Kumar",12) . Si uso var o val, la salida es 20 . Entiendo que el valor predeterminado es val en scala. Esta:

 def age = 30 age = 45 

… da un error de comstackción porque es un val por defecto. ¿Por qué el primer conjunto de líneas de arriba no funciona correctamente y, sin embargo, no genera errores?

Hay tres formas de definir las cosas en Scala:

  • def define un método
  • val define un valor fijo (que no se puede modificar)
  • var define una variable (que puede ser modificada)

Mirando tu código:

 def person = new Person("Kumar",12) 

Esto define un nuevo método llamado person . Puede llamar a este método solo sin () porque está definido como método sin parámetros. Para el método empty-paren, puede llamarlo con o sin ‘()’. Si simplemente escribes:

 person 

entonces está llamando a este método (y si no asigna el valor de retorno, simplemente se descartará). En esta línea de código:

 person.age = 20 

lo que ocurre es que primero llama al método de la person , y en el valor de retorno (una instancia de la clase Person ) está cambiando la variable del miembro de la age .

Y la última línea:

 println(person.age) 

Aquí vuelve a llamar al método de person , que devuelve una nueva instancia de la clase Person (con la age establecida en 12). Es lo mismo que esto:

 println(person().age) 

Comenzaría por la distinción que existe en Scala entre def , val y var .

  • def : define una etiqueta inmutable para el contenido del lado derecho que se evalúa de forma diferida : evaluar por nombre.

  • val : define una etiqueta inmutable para el contenido del lado derecho que se evalúa con entusiasmo / inmediatamente , se evalúa por valor.

  • var : define una variable mutable , inicialmente establecida en el contenido evaluado del lado derecho.

Ejemplo, def

 scala> def something = 2 + 3 * 4 something: Int scala> something // now it's evaluated, lazily upon usage res30: Int = 14 

Ejemplo, val

 scala> val somethingelse = 2 + 3 * 5 // it's evaluated, eagerly upon definition somethingelse: Int = 17 

Ejemplo, var

 scala> var aVariable = 2 * 3 aVariable: Int = 6 scala> aVariable = 5 aVariable: Int = 5 

De acuerdo con lo anterior, las tags de def y val no se pueden reasignar, y en caso de cualquier bash se generará un error como el siguiente:

 scala> something = 5 * 6 :8: error: value something_= is not a member of object $iw something = 5 * 6 ^ 

Cuando la clase se define como:

 scala> class Person(val name: String, var age: Int) defined class Person 

y luego instanciado con:

 scala> def personA = new Person("Tim", 25) personA: Person 

se crea una etiqueta inmutable para esa instancia específica de Persona (es decir, ‘personaA’). Siempre que sea necesario modificar el campo mutable ‘edad’, dicho bash falla:

 scala> personA.age = 44 personA.age: Int = 25 

como se esperaba, ‘edad’ es parte de una etiqueta no mutable. La forma correcta de trabajar en esto consiste en usar una variable mutable, como en el siguiente ejemplo:

 scala> var personB = new Person("Matt", 36) personB: Person = Person@59cd11fe scala> personB.age = 44 personB.age: Int = 44 // value re-assigned, as expected 

como es claro, de la referencia variable variable (es decir, ‘persona B’) es posible modificar el campo mutable de la clase ‘edad’.

Todavía destacaría el hecho de que todo proviene de la diferencia mencionada anteriormente, eso tiene que ser claro en mente de cualquier progtwigdor de Scala.

Con

 def person = new Person("Kumar", 12) 

está definiendo una función / variable diferida que siempre devuelve una nueva instancia de Persona con el nombre “Kumar” y edad 12. Esto es totalmente válido y el comstackdor no tiene motivos para quejarse. Llamar a person.age devolverá la edad de esta instancia de persona recién creada, que siempre es 12.

Cuando se escribe

 person.age = 45 

asigna un nuevo valor a la propiedad de edad en la clase Persona, que es válida ya que la edad se declara como var . El comstackdor se quejará si intenta reasignar person con un nuevo objeto Person como

 person = new Person("Steve", 13) // Error 

Para proporcionar otra perspectiva, “def” en Scala significa algo que se evaluará cada vez que se use, mientras que val es algo que se evalúa inmediatamente y solo una vez . Aquí, la expresión def person = new Person("Kumar",12) implica que siempre que usemos “persona” obtendremos una new Person("Kumar",12) llamada new Person("Kumar",12) . Por lo tanto, es natural que los dos “persona.age” no estén relacionados.

Esta es la forma en que entiendo a Scala (probablemente de una manera más “funcional”). No estoy seguro si

 def defines a method val defines a fixed value (which cannot be modified) var defines a variable (which can be modified) 

es realmente lo que Scala intenta decir sin embargo. Realmente no me gusta pensar de esa manera al menos …

Como Kintaro ya dice, la persona es un método (debido a def) y siempre devuelve una nueva instancia de Persona. Como descubriste, funcionaría si cambias el método a var o val:

 val person = new Person("Kumar",12) 

Otra posibilidad sería:

 def person = new Person("Kumar",12) val p = person p.age=20 println(p.age) 

Sin embargo, person.age=20 en tu código está permitido, ya que recuperas una instancia de person método de person , y en esta instancia puedes cambiar el valor de una var . El problema es que después de esa línea ya no tienes más referencia a esa instancia (ya que cada llamada a person producirá una nueva instancia).

Esto no es nada especial, tendrías exactamente el mismo comportamiento en Java:

 class Person{ public int age; private String name; public Person(String name; int age) { this.name = name; this.age = age; } public String name(){ return name; } } public Person person() { return new Person("Kumar", 12); } person().age = 20; System.out.println(person().age); //--> 12 

Tomemos esto:

 class Person(val name:String,var age:Int ) def person =new Person("Kumar",12) person.age=20 println(person.age) 

y reescribirlo con un código equivalente

 class Person(val name:String,var age:Int ) def person =new Person("Kumar",12) (new Person("Kumar", 12)).age_=(20) println((new Person("Kumar", 12)).age) 

Ver, def es un método. Se ejecutará cada vez que se llame, y cada vez devolverá (a) una new Person("Kumar", 12) . Y esto no es un error en la “asignación” porque no es realmente una tarea, sino solo una llamada al método age_= (provisto por var ).