Scala singleton工厂和类常量

GKe*_*lly 1 syntax scala scala-2.8

好吧,在关于'类变量作为常量'的问题中,我得到的事实是,在"官方"构造函数运行之后(即直到你有一个实例),常量才可用.但是,如果我需要伴侣单身人士在课堂上进行调用怎么办:

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
}
Run Code Online (Sandbox Code Playgroud)

如果我首先创建伴随对象,'new thing(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
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,这样做会给我一个'thing.thing'类型的对象

val t = thing(2)
Run Code Online (Sandbox Code Playgroud)

结果是

t: thing.thing = val: 84
Run Code Online (Sandbox Code Playgroud)

我提出的唯一有用的解决方案是创建一个抽象类,一个伴侣和一个内部类(扩展抽象类):

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)
Run Code Online (Sandbox Code Playgroud)

好的,'t1'仍然具有'thing.privThing'类型,但它现在可以被视为'事物'.

但是,它仍然不是一个优雅的解决方案,谁能告诉我更好的方法呢?

PS.我应该提一下,我在Windows 7上使用Scala 2.8.1

Ken*_*oom 12

首先,您看到的错误(您没有告诉我它是什么)不是运行时错误.在初始化单例thing时不会调用构造thing函数 - 稍后在调用时调用它thing.apply,因此在运行时没有循环引用.

其次,你在编译时有一个循环引用,但是当你编译你保存在磁盘上的scala文件时,这不会导致问题 - 编译器甚至可以解析不同文件之间的循环引用.(我测试过.我把你的原始代码放在一个文件中并编译它,它运行正常.)

您真正的问题来自于尝试在Scala REPL中运行此代码.以下是REPL的作用以及为什么这是REPL中的问题.你正在进入object thing,一旦你完成,REPL就会尝试编译它,因为它已经到达了一段连贯的代码.(分号推断能够在对象的末尾推断出分号,这意味着编译器可以开始处理那段代码.)但是因为你没有定义class thing它所以无法编译它.当您反转的定义,你有同样的问题class thingobject thing.

该解决方案是将两个巢class thingobject thing一些外对象物的内部.这将编译推迟,直到外部的对象是完整的,在这一点,编译器将看到的定义class thing,并object thing在同一时间.您可以在此import thingwrapper._之后运行,以在REPL的全局范围内生成class thingobject thing使用.当您准备将代码集成到某个文件中时,只需抛弃外部类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
   }   
}
Run Code Online (Sandbox Code Playgroud)