2011-12-20 1 views
4

다음 코드에서 암시 적 변환은 println(2) 행 주위에 적용됩니다. 나는 어리석게도 그것이 전체 블록 { println(1); println(2) } 주위에 적용될 것으로 예상했다. 컴파일러가 암시 적으로 배치하는 위치를 어떻게해야합니까?블록이있는 암시 적 변환 위치 선택

object Executor { 

    private var runnable: Runnable = _ 

    def setRunnable(runnable: Runnable) { 
    this.runnable = runnable 
    } 

    def execute() { runnable.run() } 

} 

object Run extends App { 

    implicit def blockToRunnable(p: ⇒ Any): Runnable = 
    new Runnable { def run() = p } 

    Executor.setRunnable { 
    println(1) 
    println(2) 
    } 

    println("Before execute") 
    Executor.execute() 

} 
+1

이상해 그! _neither_ 문에 적용하고'println (2)'의'()'(단위) 반환 값만 감싸기를 기대했을 것입니다. 두 번째 전화를 이름으로 부르는 것이 나를 매우 비 직관적으로 만든다. –

답변

3

사양에 따르면, 암시 적 변환이 때 적용됩니다 식의 형식이 예상 유형과 일치하지 않습니다. 주요 관찰은 블록 입력시 예상되는 유형이 스레드되는 방식입니다.

표현 e 유형 T의이며, T는 식의 예상 유형pt을 준수하지 않는 경우

. 이 경우 e에 적용 할 수 있고 결과 유형이 pt를 따르는 내재 된 v가 검색됩니다. 제 6.11 블록에서

, 블록의 마지막 표현식 예상 유형

최종 식 e 예상 형식으로 정의하면, 블록의 예측 타입이다.

이 스펙이 주어지면, 컴파일러는 이있는 것처럼 보입니다. 예상되는 블록 유형은 Runnable이고 예상 유형은 println(2)Runnable이됩니다.

제안 : 어떤 implicits이 적용되는지 알고 싶다면 Eclipse 용 Scala IDE 2.1에 야간 빌드를 사용할 수 있습니다. '강조 표시'할 수 있습니다.

편집 : 범위 내에서 암시 적으로 호출 이름이있는 것은 놀랍습니다.

+0

나는이 스칼라 IDE 일을 바꿔야 할 것이다 ;-) –

+0

여기에는 강조 표시에 대한 스크린 샷이있는 [다운로드] (http://scala-ide.org/download/nightly.html) 사이트가있다. :) –

4

은이 같은 이러한 동작을 합리화 : 스펙에 따른 블록 {s1; s2; ...; sn; e } 유형 마지막 표현식 e의 유형이다.

그래서 컴파일러는 e을 입력하고 유형을 Runnable으로 확인합니다. 이는 실패하므로 eRunnable으로 변환하는 암시 적 변환을 검색합니다. 그래서이 좋아하는 것 :

이이 작은 예에 scala -Xprint:typer로 확인
{ s1; s2; ... sn; convert(e) } 

:

class A 
implicit def convert(a: A): String = a.toString 
def f(s: String) { println(s) } 
f{ println(1); new A } 

인쇄 :

private[this] val res0: Unit = $line3.$read.$iw.$iw.f({ 
    scala.this.Predef.println(1); 
    $line2.$read.$iw.$iw.convert(new $line1.$read.$iw.$iw.A()) 
}); 
+0

맞아요, 나는 그것이하는 일의 메 커닉을 이해합니다 ... 그러나 컴파일러가 어떻게/왜 왜 전자로 작업하기로 결정했는지는 분명하지 않습니다. {s1; s2; ... e} 블록을 사용합니다. –

0

문제는 블록을 마치 코드 조각처럼 썽크 인 것처럼 생각한다는 것입니다. 그들은 그렇지 않습니다. { a; b; c }이 아니며은 전달할 수있는 코드입니다.

그럼 어떻게 내재물에 대한 이유를 설명해야합니까?실제로 암시 적 전환 인 보기에 대해 어떻게 판단해야합니까? 뷰는 변경해야하는 값에 적용됩니다. 귀하의 예에서

{ 
    println(1) 
    println(2) 
} 

의 값은 setRunnable으로 전달됩니다. 블록의 값은 마지막 표현식의 값이므로 println(2)의 결과를 setRunnable에 전달합니다. 즉, Unit이고 setRunnableRunnable이므로 암시 적으로 검색하여 찾았으므로 println(2)은 큰 이름으로 blockToRunnable으로 전달됩니다. 이

THERE ARE NO BLOCKS IN SCALA. 

:

결론이며, 이것이 내가 스택 오버플로에 여러 번 이미 준 조언이다 (많은 사람들이 같은 일을하려고하는) 당신의 머리에서 다음을 얻을 수 있습니다 함수는 있지만 블록은 아닙니다.

기술적으로 그 문장은 틀린 것입니다 - 스칼라에는 블록이 있지만 생각하는 바가 아니므로 완전히 제거하십시오. 깨끗한 슬레이트에서 스칼라의 블록이 후자인지 알 수 있습니다. 그렇지 않으면, 당신은 그들이하지 않는 방식으로 일하도록 유도하거나, 다른 방식으로 일할 때 특정 방식으로 일한다고 추론해야합니다.

+0

나는 생각하지 않는다고 생각합니다. ;-) 스칼라는 통어론 적 유연성을 제공하므로 코드 블록을 마치 실제로 전달할 수있는 코드 조각처럼 취급 할 수 있습니다. 이는 이름 별 매개 변수 중 하나의 큰 이점입니다! 예를 들어, 질문과 같이 구문에 문제없이 작동하는 "setRunnable (p : => Any)"메서드를 쉽게 작성할 수 있습니다. 나는 단지 컴파일러가 의외의 경우를 치고 implicits를 배치하기로 선택하는 방법에 관심이있다. –

+0

@MattR 아하, 나 오른쪽! 이름 매개 변수는 "코드 블록"과 전혀 관련이 없습니다. 그건 그렇고, 제가 생각한 것 중에 하나는 당신이 일을하지 않은 방식으로 일한다고 추론했을 때 말입니다. –

+0

"문제는 블록을 뚝뚝처럼 생각하고 있다는 것입니다." 썽크는 정확히 이름 별 평가 (http://en.wikipedia.org/wiki/Thunk_(functional_programming)#Call_by_name)에 대해 생각하는 올바른 방법입니다. –

0

나는 first scala puzzle에 주어진 설명을 많이 좋아했습니다. 출력의 일 무슨 즉

는 :

List(1, 2).map { i => println("Hi"); i + 1 } 
List(1, 2).map { println("Hi"); _ + 1 }