Vengo de experiencia en Java y soy nuevo en Scala, actualmente estoy leyendo el libro 'Programación en Scala'.
Hay un ejemplo en el libro de la siguiente manera:
class Rational(n: Int, d: Int) { // This won't compile require(d != 0) override def toString = n + "/" + d def add(that: Rational): Rational = new Rational(n * that.d + that.n * d, d * that.d) }Sin embargo, dado este código, el compilador se queja:
error: value d is not a member of Rational new Rational(n * that.d + that.n * d, d * that.d) ^ error: value n is not a member of Rational new Rational(n * that.d + that.n * d, d * that.d) ^ error: value d is not a member of Rational new Rational(n * that.d + that.n * d, d * that.d) ^La explicación dice:
Aunque los parámetros de clase n y d están dentro del alcance del código de su método add, solo puede acceder a su valor en el objeto en el que se invocó add. Por lo tanto, cuando dice n o d en la implementación de add, el compilador se complace en proporcionarle los valores para estos parámetros de clase. Pero no le permitirá decir that.n o that.d porque eso no se refiere al objeto de Rational en el que se invocó add. Para acceder al numerador y al denominador en eso, deberá convertirlos en campos.
También la implementación correcta se da a continuación:
class Rational(n: Int, d: Int) { require(d != 0) val numer: Int = n val denom: Int = d override def toString = numer + "/" + denom def add(that: Rational): Rational = new Rational( numer * that.denom + that.numer * denom, denom * that.denom ) }Traté de entender esto muchas veces, pero todavía no estaba claro.
Ya tengo los parámetros n y d a nivel de clase. Puedo acceder a ellos en el método add . Estoy pasando otro objeto de Rational al método add . También debería tener n y d , ¿verdad?
¿Qué hay de malo en that.n y that.d ? ¿Por qué necesito tomar los parámetros en los campos?
Además, el método toString anulado simplemente está tomando n y d , ¿cómo no falla eso?
Puedo sonar estúpido, pero realmente necesito entender esto claramente para obtener mejores fundamentos antes de seguir adelante.
Los parámetros que se pasan a un constructor de clase tienen como valor predeterminado miembros privados y, por lo tanto, están disponibles para todo el código de clase (como se ve en la anulación de toString ), pero no se puede acceder a ellos como miembros de instancia (por lo que that.d no funciona).
Puede decirle al compilador que no use el valor predeterminado.
class Rational(val n: Int, val d: Int) { // now it compiles ... Alternativamente, los argumentos que se pasan a una case class de forma predeterminada a los miembros de la instancia.
case class Rational(n: Int, d: Int) { // this also compiles ...Scala tiene más tipos de modificadores de acceso que Java. En Scala hay algo llamado private[this] que significa "privado para el objeto actual" que es más estricto que el private normal que significa "privado para todos los objetos de esta clase".
class Rational(n: Int, d: Int)es básicamente lo mismo que
class Rational(private[this] val n: Int, private[this] val d: Int)En un nivel más alto, casi filosófico, se podría decir que
class Rational(n: Int, d: Int) { ... } es como un método estático que devuelve un Rational y tiene parámetros n y d , y como en cualquier método, sus parámetros son locales para el método. Al calificar los parámetros con val o var , convierte esos parámetros en campos de Rational , sin tener que escribirlos dos veces: una vez como un parámetro para el método (o constructor, que es el nombre más específico para este método estático) y otra vez como un campo
Estaba leyendo el mismo libro y tenía la misma duda. Cuando descompilé el código, esto es lo que se generó.
class Employee(var age: Int)transpilado a
public class Employee { private int age; public int age() { return this.age; } public void age_$eq(final int x$1) { this.age = x$1; } public Employee(final int age) { this.age = age; super(); } }Próximo,
class Employee(val age: Int)transpilado a
public class Employee { private final int age; public int age() { return this.age; } public Employee(final int age) { this.age = age; } }Próximo,
class Employee(age: Int)transpilado a
public class Employee { public Employee(final int age) { } }Ejemplo
class Employee(age: Int) { def getAge(): Int = age }transpilado a
public class Employee { private final int age; public int getAge() { return this.age; } public Employee(final int age) { this.age = age; } }