"новое" ключевое слово в Scala
У меня очень простой вопрос - когда мы должны применять новое ключевое слово при создании объектов в Scala? Это когда мы пытаемся создавать экземпляры только Java-объектов?
2 ответа
Использовать new
ключевое слово, когда вы хотите сослаться на class
собственный конструктор:
class Foo { }
val f = new Foo
не указывать new
если вы ссылаетесь на объект-компаньон apply
метод:
class Foo { }
object Foo {
def apply() = new Foo
}
// Both of these are legal
val f = Foo()
val f2 = new Foo
Если вы сделали класс кейса:
case class Foo()
Scala тайно создает объект-компаньон для вас, превращая его в это:
class Foo { }
object Foo {
def apply() = new Foo
}
Так что вы можете сделать
f = Foo()
Наконец, имейте в виду, что нет правила, которое говорит, что спутник apply
Метод должен быть прокси для конструктора:
class Foo { }
object Foo {
def apply() = 7
}
// These do different things
> println(new Foo)
test@5c79cc94
> println(Foo())
7
И, так как вы упомянули классы Java: да - классы Java редко имеют сопутствующие объекты с apply
метод, поэтому вы должны использовать new
и конструктор фактического класса.
Это когда мы пытаемся создавать экземпляры только Java-объектов?
Не за что. Есть два общих случая, когда вы пропускаете new
в скале. С одноэлементными объектами (которые часто используются для хранения статических функций и как своего рода фабрика, похожая на ту, что вы видели в java):
scala> object LonelyGuy { def mood = "sad" }
defined module LonelyGuy
scala> LonelyGuy
res0: LonelyGuy.type = LonelyGuy$@3449a8
scala> LonelyGuy.mood
res4: java.lang.String = sad
В случае классов (на самом деле под ними есть шаблон + класс = сопутствующий шаблон, например, имеющий класс и объект с одинаковым именем):
scala> case class Foo(bar: String)
defined class Foo
scala> Foo("baz")
res2: Foo = Foo(baz)
Поэтому, когда вы работаете с простыми классами, правила такие же, как и в Java.
scala> class Foo(val bar: String)
defined class Foo
scala> new Foo("baz")
res0: Foo = Foo@2ad6a0
// will be a error
scala> Foo("baz")
<console>:8: error: not found: value Foo
Foo("baz")
Бонус, в scala есть анонимные классы, которые можно построить так:
scala> new { val bar = "baz" }
res2: java.lang.Object{val bar: java.lang.String} = $anon$1@10ee5b8
scala> res2.bar
res3: java.lang.String = baz
Это когда мы пытаемся создать только объекты Java?
Со Scala 3 (который должен быть выпущен в середине 2020 года, восемь лет спустя) на основе Dotty: никогда.
Scala 3 упадет "new
", как в этой ветке
Приложения-создатели позволяют использовать простой синтаксис вызова функций для создания экземпляров класса, даже если не реализован метод apply.
Пример:
class StringBuilder(s: String) {
def this() = this(s)
}
StringBuilder("abc") // same as new StringBuilder("abc")
StringBuilder() // same as new StringBuilder()
Приложения-создатели обобщают функциональность, предоставленную до сих пор только для классов case, но механизм, как это достигается, немного отличается.
Вместо автоматически сгенерированного метода apply мы добавляем новую возможную интерпретацию вызова функцииf(args)
.