Как мне перевести следующий код Java-конструктора в Scala? - PullRequest
1 голос
/ 16 июля 2011

Я все еще пытаюсь обернуться вокруг конструкторов Scala

public class MyClass {
    private String myString = null;

    public MyClass() {
        myString = "hello";
    }
} 

Ответы [ 2 ]

9 голосов
/ 16 июля 2011

В 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.

1 голос
/ 16 июля 2011

Ваш конструктор по умолчанию, он не принимает никаких аргументов. Это эквивалентно отсутствию конструктора и установке свойства myString как «привет». Поскольку вы определили его как val, он будет неизменным (нет эквивалента установщику Java), но вы можете получить доступ к значению myString через. нотация (например, myClass.myString)

class MyClass {
  val myString = "hello"
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...