Scala синглтон-фабрики и классовые константы - PullRequest
1 голос
/ 15 декабря 2010

ОК, в вопросе о 'Переменные класса как константы' я получаю тот факт, что константы недоступны до тех пор, пока не будет запущен «официальный» конструктор (т.е. пока у вас не будет экземпляра) , НО, что если мне понадобится спутник-одиночка для звонков в класс:

object thing {
    val someConst = 42
    def apply(x: Int) = new thing(x)
}

class thing(x: Int) {
    import thing.someConst
    val field = x * someConst
    override def toString = "val: " + field
}

Если я сначала создаю объект-компаньон, «новая вещь (x)» (в компаньоне) вызывает ошибку. Однако, если я сначала определю класс, «x * someConst» (в определении класса) вызовет ошибку.

Я также пытался поместить определение класса в синглтон.

object thing {
    var someConst = 42

    def apply(x: Int) = new thing(x)

    class thing(x: Int) {
        val field = x * someConst
        override def toString = "val: " + field
    }
}

Однако, делая это, я получаю объект типа 'thing.thing'

val t = thing(2)

Результаты в

t: thing.thing = val: 84

Единственное полезное решение, которое я нашел, - это создание абстрактного класса, компаньона и внутреннего класса (который расширяет абстрактный класс):

abstract class thing

object thing {
    val someConst = 42
    def apply(x: Int) = new privThing(x)

    class privThing(x: Int) extends thing {
        val field = x * someConst
        override def toString = "val: " + field
    }
}

val t1 = thing(2)
val tArr: Array[thing] = Array(t1)

Хорошо, у 't1' все еще есть тип 'thing.privThing', но теперь он может рассматриваться как 'вещь'.

Однако это все еще не элегантное решение, может кто-нибудь сказать мне лучший способ сделать это?

PS. Я должен отметить, что я использую Scala 2.8.1 на Windows 7

Ответы [ 2 ]

12 голосов
/ 15 декабря 2010

Во-первых, ошибка, которую вы видите (вы не сказали мне, что это), не является ошибкой во время выполнения.Конструктор thing не вызывается при инициализации синглтона thing - он вызывается позже при вызове thing.apply, поэтому во время выполнения циклическая ссылка отсутствует.

Во-вторых, у вас есть циклическая ссылкассылка во время компиляции, но это не вызывает проблем при компиляции файла scala, который вы сохранили на диске - компилятор может даже разрешать циклические ссылки между различными файлами.(Я протестировал. Я поместил ваш оригинальный код в файл и скомпилировал его, и он работал нормально.)

Ваша настоящая проблема заключается в попытке запустить этот код в Scala REPL. Вот что делает REPL и почему это проблема в REPL. Вы вводите object thing, и, как только вы закончите, REPL пытается скомпилировать его, потому что он достиг конца связногокусок кода.(Вывод точки с запятой мог вывести точку с запятой в конце объекта, и это означало, что компилятор может приступить к работе с этим фрагментом кода.) Но так как вы не определили class thing, он не может скомпилировать его.У вас возникает та же проблема, когда вы меняете определения class thing и object thing.

Решение состоит в том, чтобы вложить как 1018 *, так и object thing в некоторый внешний объект.Это будет откладывать компиляцию до тех пор, пока этот внешний объект не будет завершен, после чего компилятор увидит определения class thing и object thing одновременно.Вы можете запустить import thingwrapper._ сразу после этого, чтобы сделать class thing и object thing доступными в глобальной области для REPL. Когда вы будете готовы куда-то интегрировать свой код в файл, просто отбросьте внешний класс thingwrapper.

object thingwrapper{
   //you only need a wrapper object in the REPL
   object thing {
       val someConst = 42
       def apply(x: Int) = new thing(x)
   }   

   class thing(x: Int) {
       import thing.someConst
       val field = x * someConst
       override def toString = "val: " + field
   }   
}
0 голосов
/ 21 августа 2016

Scala 2.12 или более может принести пользу для sip 23 , который (в августе 2016 г.) перейдет к следующей итерации (считается «хорошей идеей», но является незавершенным процессом)

Типы синглтонов на основе литералов

Типы синглтонов устраняют разрыв между уровнем значений и уровнем типов и, следовательно, позволяют исследовать в Scala методы, которые обычно доступны только на языках с поддержкой полной-спектр-зависимые типы.

Система типов Scala может моделировать константы (например, 42, "foo", classOf[String]).
Они выводятся в случаях, подобных object O { final val x = 42 }.Они используются для обозначения и распространения констант времени компиляции (см. 6.24 Выражения констант и обсуждение «определения констант» в 4.1 Объявления и определения значений ).
Однако, естьнет поверхностного синтаксиса для выражения таких типов.Это заставляет людей, которые в них нуждаются, создавать макросы, которые бы предоставили обходные пути для этого (например, бесформенный ).
Это можно изменить относительно простым способом, так как в целоммеханизм для этого уже присутствует в компиляторе Scala.

type _42 = 42.type
type Unt = ().type
type _1 = 1 // .type is optional for literals
final val x = 1
type one = x.type // … but mandatory for identifiers
...