Scala параметры конструктора классов
Какая разница между:
class Person(name: String, age: Int) {
def say = "My name is " + name + ", age " + age
}
и
class Person(val name: String, val age: Int) {
def say = "My name is " + name + ", age " + age
}
Могу ли я объявить параметры как var
s и изменить их значения позже? Например,
class Person(var name: String, var age: Int) {
age = happyBirthday(5)
def happyBirthday(n: Int) {
println("happy " + n + " birthday")
n
}
}
Ответы
Ответ 1
В первой части ответа есть область действия:
scala> class Person(name: String, age: Int) {
| def say = "My name is " + name + ", age " + age
| }
scala> val x = new Person("Hitman", 40)
scala> x.name
<console>:10: error: value name is not a member of Person
x.name
Если вы префиксные параметры val
, var
, они будут видны вне класса, в противном случае они будут закрытыми, как вы можете видеть в приведенном выше коде.
И да, вы можете изменить значение var, как обычно.
Ответ 2
Это
class Person(val name: String, val age: Int)
делает поля доступными для пользователей класса, например. вы можете позже сделать
val p = new Person("Bob", 23)
val n = p.name
Если вы укажете args как var
, то область обзора будет такой же, как для val
, но поля изменяемы.
Ответ 3
Если вы знакомы с Java, вы можете получить эту идею из этого примера:
class Person(name: String, age: Int)
похож на
class Person {
public Person(String name, int age) {
}
}
Пока
class Person(var name: String, var age: Int) // also we can use 'val'
похож на
class Person {
String name;
int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
Интуиция заключается в том, что без var/val переменная доступна только внутри конструктора. Если var/val добавлен, класс будет иметь переменные-члены с тем же именем.
Ответ 4
Ответы здесь действительно хорошие, однако я занимаюсь этим изучением байтового кода. Когда вы применяете javap
в классе, он печатает пакеты, защищенные и общедоступные поля и методы пройденных классов. Я создал класс Person.scala и заполнил его следующим кодом.
class Person(name: String, age: Int) {
def say = "My name is " + name + ", age " + age
}
class PersonVal(val name: String, val age: Int) {
def say = "My name is " + name + ", age " + age
}
class PersonVar(var name: String, var age: Int) {
age = happyBirthday(5)
def happyBirthday(n: Int) = {
println("happy " + n + " birthday")
n
}
}
После компиляции кода с помощью scalac Person.scala
он генерирует три файла с именами Person.class, PersonVal.calass , PersonVar.cass
. Запустив javap
для каждого из этих файлов классов, мы увидим, как будет выглядеть эта структура:
>>javap Person.class
Compiled from "Person.scala"
public class Person {
public java.lang.String say();
public Person(java.lang.String, int);
}
В этом случае он не создавал никакой переменной класса для Person, поскольку он объявлен ни с val, ни с val, поэтому имя и возраст можно просто использовать внутри конструктора.
>>javap PersonVal.class
public class PersonVal {
public java.lang.String name();
public int age();
public java.lang.String say();
public PersonVal(java.lang.String, int);
}
В этом случае он имеет три члена два для конструктора ввода и один для члена, который мы объявили внутри конструктора. Однако у нас нет настроек для конструкторов ввода, поэтому мы не можем изменить значения.
>>javap PersonVar.class
public class PersonVar {
public java.lang.String name();
public void name_$eq(java.lang.String);
public int age();
public void age_$eq(int);
public int happyBirthday(int);
public PersonVar(java.lang.String, int);
}
Он аналогичен примеру PersonVal, но мы можем изменить значения в этом случае с помощью тех методов variable_$eq
. это не просто сокращенная версия variable =
Ответ 5
Вы можете использовать case class
, и в этом случае класс Person
будет иметь эти переменные, доступные вне класса.
case class Person(name: String, age: Int)
. Тогда следующий код будет работать, как ожидалось. val z = new Person("John", 20); z.name //John
Ответ 6
Ответ @Reza, где автор исследует байтовый код с помощью javap, помог мне лучше понять эту концепцию. Чтобы привести очень конкретный пример этого случая, пожалуйста, обратитесь к приведенному ниже сценарию, с которым я столкнулся в своем рабочем веб-приложении (Play + Scala):
Как вводить параметры в метод класса/признака в Scala
Если я не использую префикс val для введенного параметра authorizationHandler
, тогда
компилятор выдает эту ошибку:
класс MyController должен быть абстрактным, так как авторизация методаHandler в признаке AuthorizationCheck типа = > controllers.authapi.AuthorizationHandler не определен
[error] класс MyController @Inject() (authorizationHandler: AuthorizationHandler) расширяет контроллер с помощью AuthorizationCheck {
[ошибка] ^
[ошибка] обнаружена одна ошибка
Код>
К сожалению, ошибка не помогла мне определить правильную проблему с префиксом val
.
класс MyController @Inject() (авторизация valHandler: AuthorizationHandler) расширяет контроллер с авторизацией Check {
def myAction = AuthenticatedAction {implicit request = > ... }
}
Код>