Scala에서 함수를 정의하는 세 가지 방법의 차이점


92

동일한 기능을 표현하는 세 가지 방법이 주어집니다 f(a) := a + 1.

val f1 = (a:Int) => a + 1
def f2 = (a:Int) => a + 1
def f3:(Int => Int) = a => a + 1

이러한 정의는 어떻게 다릅니 까? REPL은 명백한 차이점을 나타내지 않습니다.

scala> f1
res38: (Int) => Int = <function1>
scala> f2
res39: (Int) => Int = <function1>
scala> f3
res40: (Int) => Int = <function1>

11
당신은 평가 위의 2 블록에 점에 유의해야한다 f1값이 정적으로 바인드 된 REPL 쇼에서 f1평가하는 동안 f2f3결과 표시 를 호출 하는 방법을. 특히 새 Function1[Int, Int]인스턴스는 f2또는 f3호출 될 때마다 생성 되지만 영원히 f1동일 Function1[Int, Int]합니다.
Randall Schulz

@RandallSchulz val 버전에 새 함수 인스턴스가 필요하지 않다는 점을 감안할 때이 경우 왜 def를 사용합니까?
virtualeyes

2
@virtualeyes FunctionN [...] 값을 산출하는 def를 볼 수있는 유일한 상황은 combinator parser 라이브러리에 있습니다. 함수를 생성하는 메서드를 작성하는 것은 그리 일반적이지 않으며 의미 적으로 / 기능적으로 변경되지 않는 함수의 많은 복사본을 생성하기 위해 def를 사용하지 않을 것입니다.
Randall Schulz

답변:


112

f1 정수를 취하고 정수를 리턴하는 함수입니다.

f2정수를 취하고 정수를 반환하는 함수를 반환하는 arity가 0 인 메서드입니다. ( f2나중에 REPL에 입력 하면 메서드에 대한 호출이됩니다 f2.)

f3과 동일합니다 f2. 유형 추론을 사용하지 않습니다.


6
f1A는 function하고 f2A는 method?
Freewind

17
@Freewind, 함수는라는 메서드가있는 개체입니다 apply. 방법은 방법입니다.
missingfaktor

멋진 대답입니다. 질문 : 당신은 f2에 arity가 없다고하는데 단항이 아닌가요? en.wikipedia.org/wiki/Arity "널 함수는 인수를 갖지 않습니다. 단항 함수는 하나의 인수를 사용합니다." 그냥 궁금해!
Matthew Cornell

5
@MatthewCornell f2자체는 인수를 허용하지 않습니다. 반환하는 함수 개체가 수행합니다.
missingfaktor

122

클래스 내 val에서 초기화시 평가되는 반면는 함수가 호출 def될 때 마다 평가됩니다 . 아래 코드에서 객체가 처음 사용될 때 x가 평가되지만 x 멤버에 액세스 할 때 다시 평가되지 않음을 알 수 있습니다. 반대로 y는 개체가 인스턴스화 될 때 평가되지 않지만 멤버에 액세스 할 때마다 평가됩니다.

  class A(a: Int) {
    val x = { println("x is set to something"); a }
    def y = { println("y is set to something"); a }
  }

  // Prints: x is set to something
  val a = new A(1)

  // Prints: "1"
  println(a.x)

  // Prints: "1"                               
  println(a.x)

  // Prints: "y is set to something" and "1"                                  
  println(a.y)

  // Prints: "y is set to something" and "1"                                                                                   
  println(a.y)

@JacobusR이 클래스 내부에서만 사실입니까?
Andrew Cassidy

예 : scala> var b = 5 b : Int = 5 scala> val a : (Int => Int) = x => x + ba : Int => Int = <function1> scala> a (5) res48 : Int = 10 스칼라> B = 6 B : 지능 = 6 스칼라> A (5) res49 : 지능 = 11 I 기대 된 10 (b)의 값을 반환 (5) 인라인되었다고
앤드류 캐시디

@AndrewCassidy 함수 a는 변경 불가능하며 초기화시 평가되지만 b변경 가능한 값으로 유지됩니다. 따라서에 대한 참조 b는 초기화 중에 설정되지만에 저장된 값 b은 변경 가능합니다. 재미를 위해 이제 새로운 val b = 123. 이 후에 는 이제 완전히 새로운 가치 a(5)이기 때문에 항상 11을 줄 것 b입니다.
Jack

@JacobusR 감사합니다 ... 이거 말이 되네요. 이는 함수 a가 원래 "var b"에 대한 참조를 전달하기 때문에 "어휘 범위"의 정의와 일치합니다. 나를 혼란스럽게 만든 것은 다음과 같은 것입니다. var b = 5; 발 c = b; b = 6; 다르게 행동합니다. 원래 "어휘"범위에 대한 참조를 전달하는 함수 정의가 Int와 동일한 방식으로 작동 할 것으로 기 대해서는 안됩니다.
Andrew Cassidy

3

같은 정의를 실행 데프 X = E하는 식 평가하지 않습니다 전자 . 대신 ex 가 사용될 때마다 평가 됩니다. 선택적으로, 스칼라 값 정의 구비 브로 X = E 오른쪽 측 평가 않고 , 즉 정의의 일부로서 평가한다. x 가 이후에 사용 되면 즉시 미리 계산 된 e 값으로 대체 되므로 식을 다시 평가할 필요가 없습니다.

Scala By Example by Martin Odersky

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.