[SCALA] 스칼라 - 발스의 초기화 순서
SCALA스칼라 - 발스의 초기화 순서
나는이 코드 조각이 그 파일에서로드 속성 :
class Config {
val properties: Properties = {
val p = new Properties()
p.load(Thread.currentThread().getContextClassLoader.getResourceAsStream("props"))
p
}
val forumId = properties.get("forum_id")
}
이것은 잘 작동하는 것 같군.
나는 이런 식으로, 다른 발에 속성의 초기화를 이동 loadedProperties을 시도했다 :
class Config {
val properties: Properties = loadedProps
val forumId = properties.get("forum_id")
private val loadedProps = {
val p = new Properties()
p.load(Thread.currentThread().getContextClassLoader.getResourceAsStream("props"))
p
}
}
그러나 그것은 작동하지 않습니다! (속성은 () "forum_id"properties.get에 널 (null)입니다).
왜 그 것입니까? 속성에 의해 참조 될 때 loadedProps 평가되지 않는 이유는 무엇입니까?
둘째, 이것은 비 단순 처리에 필요한 변수를 초기화 할 수있는 좋은 방법이다? 자바에서 나는 그들에게 마지막 필드를 선언하는 것이고, 생성자에서 초기화 관련 작업을 수행합니다.
스칼라에서이 시나리오에 대한 패턴이 있습니까?
감사합니다!
해결법
-
==============================
1.발스는 특성 때문에 loadedProps 전에 초기화지고,이 선언되고있는 순서로 (물론, 정확하게, 비 게으른 놈들이다)에 초기화됩니다. 초기화하기 propertiesis 때 또는 다른 말로, loadedProps은 여전히 null입니다. 여기에 가장 간단한 해결책은 등록 전에 loadedProps을 정의하는 것입니다 :
발스는 특성 때문에 loadedProps 전에 초기화지고,이 선언되고있는 순서로 (물론, 정확하게, 비 게으른 놈들이다)에 초기화됩니다. 초기화하기 propertiesis 때 또는 다른 말로, loadedProps은 여전히 null입니다. 여기에 가장 간단한 해결책은 등록 전에 loadedProps을 정의하는 것입니다 :
class Config { private val loadedProps = { val p = new Properties() p.load(Thread.currentThread().getContextClassLoader.getResourceAsStream("props")) p } val properties: Properties = loadedProps val forumId = properties.get("forum_id") }
당신은 또한 최초의 액세스에 초기화됩니다 것을 의미 loadedProps 게으른을 만들 수 있습니다 :
class Config { val properties: Properties = loadedProps val forumId = properties.get("forum_id") private lazy val loadedProps = { val p = new Properties() p.load(Thread.currentThread().getContextClassLoader.getResourceAsStream("props")) p } }
게으른 발을 사용하면 단순히 코드를 아프게하지 것이다 발스의 선언 순서 변경과 같은 코드가 리팩토링에 더 강력하다는 장점이있다.
(@NIA에 의해 제안)가 한 번만 어쨌든 사용되는 또한이 특정 선두로부터, 당신은 단지 데프으로 loadedProps을 해제 할 수 있습니다.
-
==============================
2.나는 loadedProps 단순히 단순히 데프와 함께 발을 바꾸어 기능으로 설정할 수 있습니다 여기에 생각한다 :
나는 loadedProps 단순히 단순히 데프와 함께 발을 바꾸어 기능으로 설정할 수 있습니다 여기에 생각한다 :
private def loadedProps = { // Tons of code }
이 경우 당신은 당신이 그것을 호출 할 때 호출 될 것을 확신합니다.
하지만 확실하지가이 경우에 대한 패턴이다.
-
==============================
3.좀 더 설명에 그냥 추가 :
좀 더 설명에 그냥 추가 :
귀하의 속성 필드는 여기 loadedProps 필드보다 먼저 초기화합니다. 당신이 그것을 얻을 이유 - 널 (null) 초기화하기 전에 필드의 값입니다. 모든 벌금 (- 여기에는 초기화 메소드의 코드가 여러 번 호출 할 수 있으므로), 그래서 데프 경우는, 단지 대신 일부 필드를 액세스하는 메소드 호출이다. , http://docs.scala-lang.org/tutorials/FAQ/initialization-order.html를 참조하십시오. 당신은 DEF 사용하거나 게으른 발은 그것을 해결하기 위해
왜 데프 그렇게 다른가요? 한 번만 (첫 번째와 한 통화 만 실제로 fileld의 초기화하므로) - 데프 여러 번 호출 할 수 있기 때문에, 그러나 발 그.
당신이 그것을 호출 할 때 그것은 또한 도움이 될 수 있도록 게으른 발 만 초기화 할 수 있습니다.
무엇의 또 다른 간단한 예에 무슨 :
scala> class A {val a = b; val b = 5} <console>:7: warning: Reference to uninitialized value b class A {val a = b; val b = 5} ^ defined class A scala> (new A).a res2: Int = 0 //null
보다 일반적으로 이야기 이론적 스칼라 (필드가 다른 필드가 필요)의 필드 사이의 종속성 그래프 analize 수 있고, 최종 노드로부터 초기화를 시작한다. 그러나 실제로 모든 모듈은 별도로 컴파일하고 그냥 순차적으로 초기화를 그래서 컴파일러는 심지어 (이 자바를 호출 스칼라를 호출에도 자바, 수 있습니다) 그 종속성을 알고하지 않을 수 있습니다.
그래서, 그 때문에, 심지어는 간단한 루프를 감지 할 수 있습니다 :
scala> class A {val a: Int = b; val b: Int = a} <console>:7: warning: Reference to uninitialized value b class A {val a: Int = b; val b: Int = a} ^ defined class A scala> (new A).a res4: Int = 0 scala> class A {lazy val a: Int = b; lazy val b: Int = a} defined class A scala> (new A).a java.lang.StackOverflowError
사실, 이러한 루프는 (하나 개의 모듈 내부) 이론적으로 별도의 빌드에서 검출 될 수 있지만, 그것은 꽤 분명 많이 도움이되지 않습니다.
from https://stackoverflow.com/questions/14568049/scala-initialization-order-of-vals by cc-by-sa and MIT license
'SCALA' 카테고리의 다른 글
[SCALA] 어떻게 ML 알고리즘에 대한 DataFrame 열을 벡터화? (0) | 2019.11.17 |
---|---|
[SCALA] 선물은 프로그램 종료 전에 실행되지 않습니다 (0) | 2019.11.17 |
[SCALA] 스칼라 내부 클래스 유형을 참조 (0) | 2019.11.17 |
[SCALA] 어떻게지도의 데이터 집합을 만드는 방법? (0) | 2019.11.17 |
[SCALA] 어떻게 스칼라를 사용하여 스파크 2.1 밀리 초와 타임 스탬프에 밀리 세컨드의 문자열 열을 변환하는? (0) | 2019.11.17 |