문제

Scala의 명령 줄 대체 사용 :

def foo(x: Int): Unit = {}
def foo(x: String): Unit = {println(foo(2))}

주어진

error: type mismatch;
found: Int(2)
required: String

REPL에서 과부하 된 재귀 방법을 정의 할 수없는 것 같습니다. 나는 이것이 Scala Repl의 버그라고 생각하고 그것을 제출했지만, "Wontfix : 통역사의 의미론을 감안할 때이 두 가지 방법이 컴파일되어야하기 때문에 이것을 지원할 수있는 방법을 거의 보지 못했습니다. 함께." 그는 메소드를 둘러싸는 물체에 넣는 것을 권장했습니다.

그 이유를 설명 할 수있는 JVM 언어 구현 또는 스칼라 전문가가 있습니까? 예를 들어 방법이 서로 전화하면 문제가 될 수 있지만이 경우에는 문제가 될 수 있습니까?

또는 이것이 너무 큰 의문이 있고 더 전제 조건 지식이 필요하다고 생각한다면, 누군가가 특히 JVM에서 언어 구현에 관한 책이나 사이트와 좋은 링크를 가지고 있습니까? (John Rose의 블로그와 책 프로그래밍 언어 실용주의에 대해 알고 있습니다. 그러나 그게 그것에 관한 것입니다. :)

도움이 되었습니까?

해결책

문제는 통역사가 가장 자주 바꾸다 지정된 이름을 가진 기존 요소는 과부하되지 않습니다. 예를 들어, 나는 종종 무언가를 실험하는 것을 통해 실행될 것이며 종종 test:

def test(x: Int) = x + x

조금 후에, 내가 달리고 있다고 가정 해 봅시다. 다른 실험과 나는 다른 방법을 만든다 test, 첫 번째와 관련이 없습니다.

def test(ls: List[Int]) = (0 /: ls) { _ + _ }

이것은 완전히 비현실적인 시나리오가 아닙니다. 사실, 그것은 대부분의 사람들이 통역사를 사용하는 방식이며, 종종 그것을 깨닫지 못한 채해도입니다. 통역사가 임의로 두 버전을 유지하기로 결정한 경우 test 범위에서 테스트 사용에서 의미 론적 차이를 혼란스럽게 할 수 있습니다. 예를 들어, 우리는 전화를 걸 수 있습니다 test, 우연히 통과 Int 보다는 List[Int] (세계에서 가장 가능성이없는 사고는 아닙니다) :

test(1 :: Nil)  // => 1
test(2)         // => 4  (expecting 2)

시간이 지남에 따라 통역사의 루트 범위는 다양한 버전의 메소드, 필드 등으로 엄청나게 혼란스러워 질 것입니다. 한 번에 통역사를 열어 두는 경향이 있지만, 이와 같은 과부하가 허용되면 강요 당할 것입니다. " "일이 너무 혼란스러워지면서 통역사를 자주 플러시하십시오.

JVM 또는 Scala 컴파일러의 제한이 아니며 의도적 인 설계 결정입니다. 버그에서 언급했듯이 루트 범위가 아닌 다른 내에있는 경우에도 여전히 과부하 할 수 있습니다. 수업 내에서 테스트 방법을 둘러싸는 것은 나에게 가장 적합한 솔루션 인 것 같습니다.

다른 팁

% scala28
Welcome to Scala version 2.8.0.final (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_20).
Type in expressions to have them evaluated.
Type :help for more information.

scala> def foo(x: Int): Unit = () ; def foo(x: String): Unit = { println(foo(2)) } 
foo: (x: String)Unit <and> (x: Int)Unit
foo: (x: String)Unit <and> (x: Int)Unit

scala> foo(5)

scala> foo("abc")
()

두 줄을 모두 복사하고 동시에 붙여 넣으면 대체가 수락됩니다.

다음과 같이 표시됩니다 Extempore 's 답, 과부하가 가능합니다. 다니엘의 디자인 결정에 대한 의견은 정확하지만 불완전하고 약간의 오해의 소지가 있다고 생각합니다. 아니요 무법자 과부하의 (가능하기 때문에) 그러나 쉽게 달성 할 수는 없습니다.

이를 초래하는 설계 결정은 다음과 같습니다.

  1. 모든 이전 정의를 사용할 수 있어야합니다.
  2. 매번 입력 한 모든 것을 다시 컴파일하는 대신 새로 입력 한 코드 만 컴파일됩니다.
  3. 다니엘이 언급 한 것처럼 정의를 재정의 할 수 있어야합니다.
  4. 클래스와 객체뿐만 아니라 Val 및 DEFS와 같은 구성원을 정의 할 수 있어야합니다.

문제는 ...이 모든 목표를 달성하는 방법입니다. 예제를 어떻게 처리합니까?

def foo(x: Int): Unit = {}
def foo(x: String): Unit = {println(foo(2))}

네 번째 항목부터 시작하여 a val 또는 def a 내부에서만 정의 할 수 있습니다 class, trait, object 또는 package object. 따라서 REPL은 다음과 같은 객체 내부에 정의를 넣습니다.실제 표현이 아닙니다!)

package $line1 { // input line
  object $read { // what was read
    object $iw { // definitions
      def foo(x: Int): Unit = {}
    }
    // val res1 would be here somewhere if this was an expression
  }
}

이제 JVM의 작동 방식으로 인해 일단 그 중 하나를 정의하면 확장 할 수 없습니다. 물론 모든 것을 다시 컴파일 할 수는 있지만 우리는 그것을 폐기했습니다. 따라서 다른 장소에 배치해야합니다.

package $line1 { // input line
  object $read { // what was read
    object $iw { // definitions
      def foo(x: String): Unit = { println(foo(2)) }
    }
  }
}

그리고 이것은 당신의 예제가 과부하가 아닌 이유를 설명합니다. 그것들은 두 곳에 정의됩니다. 당신이 그것들을 같은 줄에 넣으면, 그것들은 모두 정의되어 Extempore의 예에서 볼 수 있듯이 과부하가됩니다.

다른 디자인 결정에 관해서는, 각각의 새로운 패키지 가져 오기 정의 및 이전 패키지의 "RES"및 가져 오기가 서로를 쉐도 할 수 있으므로 "재정의"할 수 있습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top