Go에서 중첩 된 함수 선언 (함수 내부 함수)을 허용하지 않는 이유는 무엇입니까?


87

편집 : 내가 묻는 것이 명확하지 않은 경우 : 중첩 된 함수 선언을 허용하지 않음으로써 완화되는 문제는 무엇입니까?

Lambda는 예상대로 작동합니다.

func main() {
    inc := func(x int) int { return x+1; }
}

그러나 선언 내부의 다음 선언은 허용되지 않습니다.

func main() {
    func inc(x int) int { return x+1; }
}

중첩 함수가 허용되지 않는 이유는 무엇입니까?


흠 나는 당신 func main() { func (x int) int { return x+1; }(3) }
이이

@YasirG. 하지만 그것도 람다 죠, 그렇죠? 댓글이 없습니다 ...
corazza 2014-02-22

구문의 두 번째 예를 활성화하면 첫 번째 경우에서 지원하지 않는 기능은 무엇입니까?
Not_a_Golfer 2014

@yannbane은 람다 식이며 JS와 같은 다른 함수 내에서 함수를 선언 할 수 없다고 생각합니다. 그래서 가장 적합한 것은 람다를 사용하는 것입니다.
ymg

@Not_a_Golfer : 한 가지 가능성은 JavaScript가 수행하는 방식으로 구현하는 것입니다. 기본적으로 변수에 함수를 할당하는 것은 제어 흐름이 이러한 변수에 영향을 미치는 반면 JavaScript의 함수는 영향을받지 않기 때문에 함수를 선언하는 것과 매우 다릅니다. 즉 inc(), 실제 선언 전에 두 번째 예제에서 호출 할 수 있습니다. 그러나! 이유를 찾고 있는데 바둑에 대해 잘 모르지만이 규칙의 논리가 무엇인지 알고 싶습니다.
corazza 2014

답변:


54

이 명백한 기능이 허용되지 않는 3 가지 이유가 있다고 생각합니다.

  1. 컴파일러를 약간 복잡하게 만들 것입니다. 현재 컴파일러는 모든 함수가 최상위 수준에 있음을 알고 있습니다.
  2. 새로운 종류의 프로그래머 오류가 발생합니다. 무언가를 리팩터링하고 실수로 일부 함수를 중첩 할 수 있습니다.
  3. 함수와 클로저에 대해 다른 구문을 갖는 것은 좋은 일입니다. 클로저를 만드는 것은 함수를 만드는 것보다 잠재적으로 더 비싸므로 당신이 그것을하고 있다는 것을 알아야합니다.

그건 내 의견 일뿐입니다. 언어 디자이너의 공식적인 발표를 보지 못했습니다.


2
Pascal (적어도 Delphi의 화신)은 정확하고 간단합니다. 중첩 함수는 일반 함수처럼 작동하지만 둘러싸는 함수 범위의 변수에 액세스 할 수도 있습니다. 나는 이것이 구현하기 어렵다고 생각하지 않습니다. 반면에 델파이 코드를 많이 작성했는데 중첩 함수가 꼭 필요한지 잘 모르겠습니다. 가끔 멋지게 느껴지지만 둘러싸는 함수를 날려 버리는 경향이있어 읽기 어렵습니다. 또한 부모의 인수에 액세스하면 이러한 변수가 암묵적으로 액세스되므로 (정식 매개 변수로 전달되지 않음) 프로그램을 읽기가 어려울 수 있습니다.
kostix

1
로컬 함수는 메서드를 추출하는 중간 리팩토링 단계로 유용합니다. C #에서는 둘러싸는 함수에서 변수를 캡처 할 수없는 정적 로컬 함수를 도입 한 후 이러한 기능을 더욱 유용하게 만들었으므로 매개 변수로 무엇이든 전달해야합니다. 정적 로컬 funcitons는 포인트 3을 문제가되지 않습니다. 포인트 2는 내 관점에서도 문제가되지 않습니다.
Cosmin Sontu

47

물론입니다. 변수에 할당하기 만하면됩니다.

func main() {
    inc := func(x int) int { return x+1; }
}

4
주목할 가치가있는 것은 이러한 함수 (포함)를 재귀 적으로 호출 할 수 없다는 것입니다.
Mohsin Kale

26

자주 묻는 질문 (FAQ)

Go에 기능 X가없는 이유는 무엇입니까?

모든 언어에는 새로운 기능이 포함되어 있으며 누군가가 좋아하는 기능은 생략되어 있습니다. Go는 프로그래밍의 정확성, 컴파일 속도, 개념의 직교성, 동시성 및 가비지 수집과 같은 기능을 지원해야하는 필요성을 고려하여 설계되었습니다. 적합하지 않거나, 컴파일 속도 나 디자인의 명확성에 영향을 미치거나 기본 시스템 모델을 너무 어렵게 만들기 때문에 좋아하는 기능이 누락 될 수 있습니다.

Go에 기능 X가 누락되어 귀찮다면 Google을 용서하고 Go의 기능을 조사하십시오. X의 부족을 흥미로운 방식으로 보상한다는 것을 알 수 있습니다.

중첩 함수 추가의 복잡성과 비용을 정당화하는 것은 무엇입니까? 중첩 함수 없이는 할 수없는 일을 yau가하고 싶습니까? 등등.


19
공정하게 말하면, 중첩 함수를 허용하는 것이 야기 할 수있는 특별한 복잡성을 누구도 보여주지 않았다고 생각합니다. 또한 인용 된 철학에 동의하지만 중첩 된 함수를 "기능"이라고 부르는 것이 합리적 일지 모르겠습니다. 중첩 함수를 허용하는 것이 허용 할 수있는 합병증을 알고 있습니까? 나는 그들이 람다에 대한 통사론 적 설탕이라고 가정하고 있습니다 (다른 합리적인 행동은 생각할 수 없습니다).
joshlf

go가 컴파일되었으므로이 AFAIK를 수행하는 유일한 방법은 람다를 정의하는 또 다른 구문을 생성합니다. 그리고 나는 그것에 대한 사용 사례를 실제로 보지 못했습니다. 실시간으로 생성 된 정적 함수 내에 정적 함수를 가질 수 없습니다. 함수를 정의하는 특정 코드 경로를 입력하지 않으면 어떻게 될까요?
Not_a_Golfer 2014

람다 인터페이스 {}를 전달하고 assert를 입력하면됩니다. 예 : f_lambda : = lambda (func () rval {}) 또는 프로토 타입이 무엇이든. func decl 구문은 이것을 지원하지 않지만 언어는 완전히 지원합니다.
BadZen 2015-04-27


8

Go에서 중첩 된 함수가 허용됩니다. 외부 함수 내의 지역 변수에 할당하고 해당 변수를 사용하여 호출하기 만하면됩니다.

예:

func outerFunction(iterations int, s1, s2 string) int {
    someState := 0
    innerFunction := func(param string) int {
        // Could have another nested function here!
        totalLength := 0
        // Note that the iterations parameter is available
        // in the inner function (closure)
        for i := 0; i < iterations; i++) {
            totalLength += len(param)
        }
        return totalLength
    }
    // Now we can call innerFunction() freely
    someState = innerFunction(s1)
    someState += innerFunction(s2)
    return someState
}
myVar := outerFunction(100, "blah", "meh")

내부 함수는 종종 로컬 고 루틴에 유용합니다.

func outerFunction(...) {
    innerFunction := func(...) {
        ...
    }
    go innerFunction(...)
}

이동 중 폐쇄는 일반 기능과 일부 측면에서 다릅니다. 예를 들어 클로저를 재귀 적으로 호출 할 수 없습니다.
Michał Zabielski

7
@ MichałZabielski : 정의하기 전에 선언하면 재귀 적으로 호출 할 수 있습니다.
P Daddy

1

()끝에 추가 하여 즉시 호출하면됩니다 .

func main() {
    func inc(x int) int { return x+1; }()
}

편집 : 함수 이름을 가질 수 없으므로 즉시 호출되는 람다 함수 일뿐입니다.

func main() {
    func(x int) int { return x+1; }()
}

1
어 그 하나는 함수 정의의 무엇을 기대에 부합하지 않는다
corazza

1
@corazza 아, 질문을 읽을 때 "선언"이라는 단어를 놓쳤습니다. 내 잘못이야.
Nick

1
@corazza 또한 구문도 망쳤습니다. 함수 이름을 제거하는 데 필요합니다. 따라서 기본적으로 즉시 호출되는 람다 함수입니다.
Nick
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.