2013-07-19 2 views
25

익명 함수에서 명시 적 return 문 (return 키워드를 사용하는 문)이 익명 함수 자체가 아닌 동봉 된 명명 된 함수에서 반환되는 이유는 무엇입니까?익명 함수에서 스칼라 반환 문

예. 유형 오류에 다음 프로그램 결과 :

def foo: String = { 
    ((x: Integer) => return x) 
    "foo" 
} 

나는 return 키워드를 피하기 위해 권장 알지만, 명시 적 및 암시 적 반환 문은 익명 함수에서 다른 의미를 가질 이유에 관심이 있어요.

다음 예제에서는 m 실행이 끝난 후 return 문이 "생존"하고 프로그램 결과가 런타임 예외가 발생합니다. 익명의 함수가 내부 함수에서 반환되지 않으면 해당 코드를 컴파일 할 수 없습니다.

def main(args: Array[String]) { 
    m(3) 
} 

def m: (Integer => Unit) = 
    (x: Integer) => return (y: Integer) => 2 

답변

16

공식적으로 말하기 복귀는 항상 그래서 람다에서 다른 의미가없는 가장 가까운 바깥라는 이름의 방법

A return expression return e must occur inside the body of some enclosing named method or function. The innermost enclosing named method or function in a source program, f , must have an explicitly declared result type, and the type of e must conform to it. The return expression evaluates the expression e and returns its value as the result of f . The evaluation of any statements or expressions following the return expression is omitted.

에서 돌아으로 정의된다. 주름은 일반적인 방법과는 달리, 람다에서 생성 된 클로저는 둘러싼 메소드에 대한 호출을 벗어날 수 있으며 그러한 클로저에서 리턴이 있으면 예외를 얻을 수 있다는 것입니다.

If the return expression is itself part of an anonymous function, it is possible that the enclosing instance of f has already returned before the return expression is executed. In that case, the thrown scala.runtime.NonLocalReturnException will not be caught, and will propagate up the call stack.

이제 "이유"에 대해. 하나의 덜 이유는 미학입니다 : 람다는 표현식이며 어떤 표현식과 모든 하위 표현식이 중첩 구조와 상관없이 동일한 의미를 가질 때 좋습니다. http://gafter.blogspot.com/2006/08/tennents-correspondence-principle-and.html

명령형 프로그래밍에서 일반적으로 사용되는 제어 흐름 형식을 쉽게 시뮬레이션 할 수 있지만 여전히 고차원 함수로 추상화 할 수 있습니다. 장난감의 예로, Java의 foreach 구조 (for (x : xs) { yada; })를 사용하면 루프 내부로 돌아갈 수 있습니다. 스칼라에는 foreach라는 언어 수준이 없습니다. 대신에 foreach를 라이브러리에 넣습니다 (foreach에 그냥 desugar하기 때문에 "표현식"을 수확하지 않습니다). 로컬이 아닌 리턴 값을 가짐으로써 Java foreach를 가져 와서 직접 스칼라 foreach로 변환 할 수 있음을 의미합니다.

BTW, Ruby, Smalltalk 및 Common Lisp (내 머리 꼭대기에서 벗어남)도 유사한 "비 로컬"반환 값을가집니다.

+0

의미의 차이가 필요한 이유에 대해 좀 더 진지한 예가 있습니까? 나열된 것은 프리디 케이트 매개 변수가있는 수정 된'foreach'로 쉽게 에뮬레이트 될 수 있기 때문입니다. – corazza

3

return 키워드는 (클래스) 메소드 용으로 예약되었으므로 함수에서 사용할 수 없습니다.

object Foo { 
    val bar = (i: Int) => return i + i 
} 

<console>:42: error: return outside method definition 
     object Foo { val bar = (i: Int) => return i + i } 
             ^

는 대부분이 구문 메소드를 호출 좋아하기 때문에 함수의 apply 방법은 행동으로, 동일하게 방법과 기능을 처리 할 수 ​​제공하고, 소위 : 당신은 쉽게 것을 테스트 할 수 있습니다 메소드가 함수 인수로 전달되도록 허용하는 η 확장.

이 경우 차이가 있습니다. 방법으로 정의 할 때, 그것은 법적 : 요약

object Foo { 
    def bar(i: Int): Int = return i + i 
} 

, 당신은 단지 조건 (초기) 반환을 허용 방법에 return를 사용해야합니다. 메서드 대 함수에 대한 설명은 this post을 참조하십시오.

+0

이 답변은 실제로 언어 디자인이 그 결정에 이성을 나타내고있는 이유 *에 해당합니다. – corazza

+0

@jcz 매우 흐릿하고 직관력이 떨어집니다. lambdas를 생각해보십시오. 'xs.foreach {x => if (x == y) return x}'와 같은 것. –