Ключевое слово «новое» в Scala

96

У меня очень простой вопрос - когда мы должны применять ключевое слово new при создании объектов в Scala? Это когда мы пытаемся создать только объекты Java?

Bober02
источник

Ответы:

146

Используйте 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:

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и фактический конструктор класса.

Оуэн
источник
1
Класс Java никогда не может иметь сопутствующего объекта. Он может иметь объект, который может работать как Factory для класса Java, но этот объект не является его сопутствующим объектом.
kiritsuku
@Antoras Поскольку классы Scala компилируются в байт-код Java и могут распространяться в скомпилированной форме, может ли Scala отличить фактический компаньон Scala от класса с именем Foo $ со статическим членом MODULE $?
Owen
1
Я думаю, что scalac может отличаться от этого, потому что указано, что сопутствующий объект должен быть объявлен в том же файле, что и его сопутствующий класс. Поскольку сопутствующее «свойство» существует только в Scala, а не на уровне байт-кода, скаляр должен проверять код Scala, а не байт-код, чтобы быть уверенным в соблюдении спецификации.
kiritsuku
1
Любые примеры классов Java, которые НЕ используют ключевое слово new в Scala?
Bober02
Кроме того, методы объекта-компаньона также будут доступны через статические методы класса, а этого никогда не произойдет с классами java, для которых вы позже определите «сопутствующего баннера».
drexin
16

Это когда мы пытаемся создать только объекты java?

Не за что. Есть два общих случая, когда вы пропускаете newв scala. С одноэлементными объектами (которые часто используются для хранения статических функций и как своего рода фабрика, похожая на то, что вы можете видеть в 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

С классами case (на самом деле, внизу есть шаблон class + object = companion , например, имеющий класс и объект с тем же именем):

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
ом Ном ном
источник
1
Ты в порядке, дружище?
Джейкоб Би
0

Это когда мы пытаемся создать только объекты 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).

VonC
источник