7

익명 함수를 만들기위한 자리 표시 자로 _을 사용하고 있으며 문제는 스칼라가 내 코드를 변환하는 방법을 예측할 수 없다는 것입니다. 좀 더 정확하게 말해서, 그것은 내가 원하는 익명의 함수가 얼마나 "커다란"것인지를 실수로 결정합니다.익명 기능을 정의하기 위해 밑줄을 관리하는 규칙은 무엇입니까?

List(1,2,3) foreach println(_:Int) //error ! 
List(1,2,3) foreach (println(_:Int)) //work 
List(1,2,3) foreach(println(_:Int)) //work 

내가 스칼라는 "큰 익명 함수"로 첫 번째 변환 볼 수 있습니다 -Xprint:typer 사용 :

x$1 => List(1,2,3) foreach(println(x$1:Int)) 

피 가공 2 일 제 3 회 내가 원하는 무엇에 바로 변환합니다.

... foreach (x$1 => println(x$1:Int)) 

왜 이렇게할까요? 규칙이란 무엇입니까?

답변

8

간단한 규칙 밑줄의 범위를 결정하기 : 밑줄 방법에 인수가

  1. 을 그 범위 밖에 있어서, 아래에서 달리 규정 해당 할 것이다;
  2. 밑줄이() 또는 {}로 구분 된 표현식 안에있는 경우 밑줄이 포함 된 가장 안쪽의 구분 기호가 사용됩니다.
  3. 다른 모든 것들이 동일 할 경우 가능한 가장 큰 표현이 사용됩니다.

따라서 # 1 규칙에 따라 println((x: Int) => x) 대신 범위가 println 외부에 배치됩니다.

룰 # 2에 의해 후자의 두 예는 괄호로 구분 된 함수를 가지므로 (x => println(x: Int))입니다.

규칙 # 3에 의해 첫 번째 예제는 구분 기호가 없으므로 전체 표현식이됩니다.

4

나는 Sobral 씨의 대답이 잘못되었다고 생각합니다. 실제 규칙은 Scala Language Reference, 섹션 6.23, 하위 헤드 "익명 함수에 대한 자리 표시 자 구문"에서 찾을 수 있습니다.

유일한 규칙은 가장 밑의 표현식에 밑줄이 제대로 포함되어있어 익명 기능의 범위를 정의한다는 것입니다. 즉, Sobral의 처음 두 규칙은 정확합니다. 메서드 호출은 표현식이고 괄호로 묶는 것은 그 의미를 바꾸지 않기 때문입니다. 그러나 세 번째 규칙은 진리의 반대입니다. 다른 모든 것은 평등합니다. 가장 작은 표현이 사용됩니다.

Laskowski가 그의 첫 번째 사례에서 관찰 한 행동에 대한 나의 설명은 다소 복잡하고 추측입니다. When

List(1,2,3) foreach println(_:Int) 

은 Scala read-eval-print 루프에 입력됩니다.오류 메시지는 다음과 같습니다

error: type mismatch; 
found : Unit 
required: Int => ? 
       List(1,2,3) foreach println(_:Int) 
             ^

당신은 예를 작은 조금 다를 경우

List(1,2,3).foreach println(_:Int) 

오류 메시지가 감각 할 쉽다 -

error: missing arguments for method foreach in class List; 
follow this method with `_' if you want to treat it as a partially applied function 
      List(1,2,3).foreach println(_:Int) 
        ^

일을 이해하기를 조금 더 좋으면 scala을 호출하십시오 : scala -Xprint:parser. 모든 표현식이 사용자에 의해 입력 된 후, 파서에 의해 표현 된 결과가 인쇄됩니다. Laskowski의 제 (예를 들어, 많은 쓰레기, I는 생략 할 것이다.와 함께), 파서 이해할 발현 번째 예

((x$1: Int) => List(1, 2, 3).foreach(println((x$1: Int)))) 

이다 파서의 버전

((x$1: Int) => List(1, 2, 3).foreach.println((x$1: Int))) 

인 분명히 범위 구조 규칙은 표현 구조가 완전히 완성되기 전에 적용됩니다. 두 경우 모두 파서는 더 이상 사실이 아닌 괄호가 삽입 되더라도 가장 작은식이 List에서 시작한다는 것을 추측합니다. 두 번째 예에서는 해당 가정에 덧붙여 println이 식별자이기 때문에 foreach println은 첫 번째 인수가없는 인수 체인 것을 가정합니다. 의 오류는 println의 오류 전에 캐치되어 마스크됩니다. println의 오류는 그 결과가 Unit이고, foreach은 기능이 필요하다는 것입니다. 구문 분석 트리를보고 나면 이것이 정확한지 쉽게 알 수 있지만 구문 트리가 왜 그런지 분명하지 않습니다.

관련 문제