2016-09-19 3 views
3

scala에서 "handwritten enumeration"초기화에서 버그를 발견했습니다. 물체가 안에있는 것은 sealed case classobject SomeCode이므로 필기체입니다.스칼라 객체 초기화 버그

재미있는 것 - sealed case class에 기본값이있는 경우 - 어두운 마술이 발생합니다. 우리가 object SomeCode 시작의 초기화 SomeCode.Fist를 호출 할 때

import com.blabla.SomeCode 
import org.scalatest.{Matchers, WordSpec} 

class SomeCodeTest extends WordSpec with Matchers { 
    "SomeCode" should { 
    "work properly" in { 
     println(SomeCode.First.toString) 
    } 
    } 
} 

:

sealed case class SomeCode(
    id: String, 
    legend: String) 

object SomeCode { 

    object First  extends SomeCode(id = "First", legend = "first legend") 
    object Second  extends SomeCode(id = "Second", legend = "second legend") 

    val values = Seq(
    SomeCode.First, 
    SomeCode.Second) 

    private val CACHE: Map[String, SomeCode] = { 
    val ids = values.map(_.id) 
    (ids zip values).toMap 
    } 

    def getById(id: String): Option[SomeCode] = CACHE.get(id) 
} 

그리고 하나의 테스트 : 예를 들어 우리처럼 보인다 "필기 열거"를 가지고있다. 따라서 val valuesprivate val CACHE에 대한 초기화도 실제로 시작됩니다. 우리는 우리의 sealed case class에 대한 기본 값을 소개하면

하지만 ... :

sealed case class SomeCode(
    id: String, 
    legend: String = "default legend") 
... 
object First  extends SomeCode(id = "First") 
object Second  extends SomeCode(id = "Second") 

지금 우리의 테스트를 실행 - 우리가 CACHE에서 NPE있을 것이다.

SomeCode.First -이 값은 입니다. 따라서 values.map(_.id)은 NPE를 발생시킵니다. 테스트에서 우리는 SomeCode.Second를 호출 할 경우 null 내가 그것을가이 sealed case class 확장하는 좋은 방법이 아닙니다 알지만, 그럼에도 불구하고 제대로 작동해야 SomeCode.Second

에있을 것입니다. 어쩌면 내가 스칼라에서 뭔가를 이해하지 못할 수도 있지만, 현재 그것은 나를 위해 컴파일러 버그처럼 보입니다.

scalaVersion := "2.11.7"

또한 나는 스칼라 - 랭에 문제를 만들 :

val values = Seq(SomeCode.First, SomeCode.Second) : 우리가 SomeCode.First.toString를 호출 할 때 SomeCode.First 다음 코드에 null로 끝나는되기 때문에 문제가 일어나고 https://issues.scala-lang.org/browse/SI-9929

+0

가 뭔가 코드 예제에 없음을 수 있을까? 왜냐하면, 주어진 코드로 당신이 묘사하는 행동을 재현 할 수 없기 때문입니다. 즉, 'Works fine for me' –

+0

@SaschaKolberg는 기본값 인'legend : String = "default legend")로 잘 작동하고 확장 객체에이 값을 설정하지 않습니다. – invis

+0

아니요, 그렇지 않습니다. –

답변

2

위의 내용은 REPL에 값 출력을 인쇄하여 확인할 수 있습니다.

흥미롭게도, 다음 코드로 REPL 출력 살펴 :

sealed case class SomeCode(
    id: String, 
    legend: String = "default") 

object SomeCode { 
    println("begin object init") 
    object First extends SomeCode(id = "First"){println("initializing First")} 
    object Second extends SomeCode(id = "Second"){println("initializing Second")} 
    println(SomeCode.First) 
    println(SomeCode.Second) 
} 

SomeCode.First 

// REPL Output: 
begin object init 
null <--- SomeCode.First is null!!! Why does it not initialize the First object? 
initializing Second <--- Correctly initializes the Second object. 
SomeCode(Second,default) 
initializing First <--- Now starts to initialize the First object 
res41: SomeCode.First.type = SomeCode(First,default) 
+0

감사합니다. 이것이 제 질문의 핵심입니다. 흥미로운 것은 First를'Object First extends SomeCode (id = "First", "notDefault")'로 변경하면 모두 괜찮을 것이다. 또는'Object SomeCode {'객체의 이름을 SomeCodes {' – invis

+0

'로 바꿉니다. 하하 정확히'SomeCodes' 변형을 시도해 보았습니다. 그러나 무슨 일이 벌어지고 있는지 모르겠다. – Samar