В Scala вы бы просто сделали
class MyClass {
private var myString = "hello"
}
Это не похоже на то же самое, не так ли? Но давайте посмотрим на байт-код для того, что фактически производит код Java (давайте назовем этот класс JavaConstructor
):
public JavaConstructor();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: aload_0
5: aconst_null
6: putfield #2; //Field myString:Ljava/lang/String;
9: aload_0
10: ldc #3; //String hello
12: putfield #2; //Field myString:Ljava/lang/String;
15: return
Java эффективно скопировала private String myString = null;
в конструктор (обратите внимание на строки 5 и 6, где null
создается и сохраняется). Так что вся эта установка myString
в null
была пустой тратой усилий; Вы загружаете это и затем немедленно перезаписываете это.
Теперь, если мы посмотрим на соответствующую Scala:
public ScalaConstructor();
Code:
0: aload_0
1: invokespecial #18; //Method java/lang/Object."<init>":()V
4: aload_0
5: ldc #20; //String hello
7: putfield #10; //Field myString:Ljava/lang/String;
10: return
}
мы видим, что это так эффективно, как можно было бы надеяться (и отражает код).
Тогда возникает вопрос: почему вы можете захотеть сделать это так, как вы делали в Java? Ну, может быть, у вас есть несколько конструкторов, и некоторые из них установят myString
, а некоторые нет! Установка null
- это способ напомнить себе, что вам лучше инициализировать его, прежде чем использовать.
Но Скала не позволит тебе сделать это. Scala действительно позволяет только один конструктор; остальные просто псевдонимы, которые вызывают этот один конструктор. Вы можете сделать его приватным и загружать его множеством параметров, если вам нужно, но дело в том, что наличие нескольких конструкторов, некоторые из которых устанавливают критические данные, а некоторые нет, на самом деле является довольно склонным к сбоям процессом. Лучше сделать это только один раз и написать что-то вроде
private var myString = if (someParameter) "hello" else null
если вам действительно нужно это сделать. Опять же, может быть, вы только сделали его var
, потому что вы пытались установить его по-разному в разных конструкторах. С одним конструктором, может быть, в этом нет необходимости:
private val myString = if (someParameter) "hello" else null
Но, может быть, теперь, когда он установлен правильно, нам не нужно, чтобы он был приватным.
val myString = if (someParameter) "hello" else null
и, возможно, если он часто не установлен, вместо этого мы должны использовать опцию:
val myString = if (someParameter) Some("hello") else None
и тогда у вас будет нечто, похожее на идиоматическую Scala.