2010-06-27 3 views
11

스칼라 컴파일러는 종종 메서드에 대한 반환 형식을 유추 할 수 있지만 반환 형식을 지정해야하는 경우가 있습니다. 예를 들어 재귀 메서드는 반환 형식을 지정해야합니다.스칼라의 메서드에 반환 형식이 필요한 경우는 언제입니까?

가끔 "오버로드 된 메서드 (methodname)에 return type이 필요합니다"라는 오류 메시지가 표시되지만 오버로드 된 메서드에 대해 항상 반환 형식을 지정해야한다는 일반적인 규칙이 아닙니다. 이 오류).

일반적인 메서드 및 특히 오버로드 된 메서드에 대해 반환 형식을 지정해야하는 경우는 언제입니까? Programming Scala 책의

+4

, 내가 가장 간단한 방법 (아무 조건 논리와 기본적으로, 한 - 라이너)를 제외한 모든 명시 적 반환 형식을 제공합니다. 컴파일러에서 메소드의 결과 유형을 추측하게하면 원하는 것보다 더 구체적 일 수 있습니다. (예 :'Map' 대신'HashMap'을 사용합니다.) –

+0

@Randall 예, 좋은 점 (너무 명확한 반환 유형에 대해). – Jesper

답변

18

Chapter 2. Type Less, Do More는 언급 :

명시 유형 주석이 필요한 경우.

메소드의 반환 값을 다음과 같은 경우 : 실제적인 관점에서

, 당신은 다음과 같은 상황에 대한 명시 적 유형의 주석을 제공해야

  • 하는 것은 명시 적으로 심지어 방법에서 수익을 (호출 할 때 끝).
  • 메서드가 재귀 인 경우.
  • 메서드가 오버로드되고 메서드 중 하나가 다른 메서드를 호출 할 때. 호출하는 메소드에는 반환 형식 주석이 필요합니다.
  • 유추 된 반환 유형이 의도 한 것보다 일반적인 경우 (예 : Any).

예 :

// code-examples/TypeLessDoMore/method-nested-return-script.scala 
// ERROR: Won't compile until you put a String return type on upCase. 

def upCase(s: String) = { 
    if (s.length == 0) 
    return s // ERROR - forces return type of upCase to be declared. 
    else 
    s.toUpperCase() 
} 

오버로드 방법 때로는 명시 적 반환 유형을 요구할 수 있습니다. 하나의 메소드가 다른 메소드를 호출 할 때,이 예에서와 같이 호출을 수행하는 메소드에 리턴 유형을 추가해야합니다.

joiner 방법

// code-examples/TypeLessDoMore/method-overloaded-return-script.scala 
// Version 1 of "StringUtil" (with a compilation error). 
// ERROR: Won't compile: needs a String return type on the second "joiner". 

object StringUtil { 
    def joiner(strings: List[String], separator: String): String = 
    strings.mkString(separator) 

    def joiner(strings: List[String]) = joiner(strings, " ") // ERROR 
} 
import StringUtil._ // Import the joiner methods. 

println(joiner(List("Programming", "Scala"))) 

함께 문자열을 연결 List.
첫 번째 방법은 구분 기호 문자열에 대한 인수도 취합니다.
두 번째 메서드는 첫 번째 메서드를 단일 공간의 "기본"구분 기호로 호출합니다.

이 스크립트를 실행하면 다음 오류가 발생합니다. 두 번째 joiner 방법은 첫 번째 호출 이후

... 9: error: overloaded method joiner needs result type 
def joiner(strings: List[String]) = joiner(strings, "") 

, 그것은 명시 적 String 반환 형식이 필요합니다.그것은 다음과 같이한다 : 기본적으로

def joiner(strings: List[String]): String = joiner(strings, " ") 

, 를 스칼라가을 추론 할 수 있지만 좋은 방법이 될 수 반환 형식을 지정.


Randall Schulz 의견 : (개인) 스타일의 문제로

, 내가 가장 간단한 방법 (아무 조건 논리와 기본적으로, 한 - 라이너)를 제외한 모든 명시 적 반환 형식을 제공합니다.

컴파일러에서 메서드의 결과 형식을 유추하면 원하는 것보다 더 구체적일 수 있습니다. (예를 들어, 대신지도의 HashMap.)

을 그리고 당신은 당신의 반환 형식에서 최소한의 인터페이스를 노출 할 수 있기 때문에 (예를이 SO question 참조), 추론 이런 종류의 방법으로 얻을 수 있습니다. 당신은 확인하기 위해 컴파일러를 할 때

는 반환 유형을 지정합니다


그리고 ("추정 된 반환 형식은 당신이 의도 한 것보다 더 일반적인 것") 마지막 시나리오에 대해, Ken Bloom가 추가

기능에서 해당 코드 유형은 당신이

(기대 수익 형보다 "더 일반적인 트리거 결함이있는 코드를 예상 반환했습니다 :

내가 잘못 해석하고
// code-examples/TypeLessDoMore/method-broad-inference-return-script.scala 
// ERROR: Won't compile. Method actually returns List[Any], which is too "broad". 

def makeList(strings: String*) = { 
    if (strings.length == 0) 
    List(0) // #1 
    else 
    strings.toList 
} 

val list: List[String] = makeList() // ERROR 

, 목록 [모든] 빈 목록을 반환하지만, 켄을 불러 때문에 :

List(0)

0 요소 목록을 작성하지 않습니다.
하나의 요소 (값 0)를 포함하는 List[Int]을 만듭니다.
따라서 하나의 조건부 분기에서 List[Int]과 다른 조건부 분기에서 List[String]List[Any]으로 일반화됩니다.
이 경우 타이프가 지나치게 일반적인 것은 아닙니다. 코드의 버그입니다.
) (개인) 스타일의 문제로

+0

"유추 된 반환 유형이 의도 한 것보다 일반적 일 때 (예 : Any) 이것은 이상합니다. 사실, Typer의 버그라고 생각합니다. 나는 그런 경험을 한번도하지 못했습니다. 모범이 있습니까? – soc

+0

@soc : http://programming-scala.labs.oreilly.com/ch02.html에는 리턴 타입을 지정하지 않는 한'List (0)'(사이즈 0의'List')가 반환 될 것이고'List [String]'대신'List [Any]'를 반환하는 한 가지 예가 있습니다. – VonC

+2

'List (0)'은 원소가 0 인리스트를 생성하지 않습니다. 그것은 한 요소 (값'0')를 포함하는 List [Int]를 생성합니다. 따라서 하나의 조건 분기에있는 List [Int]와 다른 조건 분기에있는 List [String]은'List [Any] '로 일반화됩니다. 이 경우, 타이 퍼는 지나치게 일반 적이 지 않습니다. 이는 코드의 버그입니다. 반환 형식을 지정하는 또 다른 규칙을 추가합니다. ** 컴파일러에서 함수의 코드가 예상 한 형식을 반환하는지 확인하려고 할 때 반환 형식을 지정하십시오. ** –