스칼라의 적용 기능은 무엇입니까?


311

나는 고안된 언 마샬링과 동사 명사 ( AddTwo클래스에 apply두 가지를 더한!) 예제 에서 그것을 이해하지 못했습니다 .

나는 그것이 구문 설탕이라는 것을 이해하므로 (나는 문맥에서 추론) 일부 코드를보다 직관적으로 만들도록 설계되어야합니다.

apply함수 가있는 클래스는 어떤 의미를 갖 습니까? 어떤 용도로 사용되며 어떤 목적으로 코드를 개선합니까 (비 정렬 화, 동사 명사 등)?

컴패니언 객체에서 사용될 때 어떻게 도움이됩니까?


4
빠른 인터넷 검색조차도 많은 훌륭한 기사를 제공합니다. 여기에 하나가 있습니다 : jackcoughonsoftware.blogspot.com/2009/01/…
om-nom-nom


6
실제로 이것은 Java / C ++의 생성자와 동일하지만 값을 반환 할 수 있으며 '적용'이름을 갖습니다.
ses

함수가 아니라 메서드입니다. 스칼라에서는 메소드와 함수의 구별이 매우 중요합니다.
rightfold

1
Zoidberg에 대해 자세히 설명하기 위해 "방법은 클래스의 상태에 액세스 할 수있는 함수일뿐입니다" twitter.github.io/scala_school/basics.html 일반적으로 이것은 Scala stackoverflow.com/questions/155609/…
DharmaTurtle

답변:


640

수학자들은 자신 만의 재미있는 방법을 가지고 있기 때문에 프로그래머가 말하는 것처럼 " f그것을 함수 를 x매개 변수로 전달하는 것 "이라고 말하는 대신 " f인수에 함수 적용 하기 "에 대해 이야기 x합니다.

수학과 컴퓨터 과학에서 Apply는 함수를 인수에 적용하는 함수입니다.
위키 백과

applyScala의 객체 지향 패러다임과 기능 패러다임 사이의 격차를 메우기위한 목적으로 사용됩니다. 스칼라의 모든 기능은 객체로 표현 될 수 있습니다. 모든 함수에는 OO 유형도 있습니다. 예를 들어 Int매개 변수를 사용하고을 반환하는 함수 Int는 OO 유형이 OO입니다 Function1[Int,Int].

 // define a function in scala
 (x:Int) => x + 1

 // assign an object representing the function to a variable
 val f = (x:Int) => x + 1

모든 것이 스칼라의 객체이기 때문에 f이제 객체에 대한 참조로 취급 될 수 있습니다 Function1[Int,Int]. 예를 들어, 함수에는 메소드가 없기 때문에 순수 함수로는 불가능했던 toString에서 상속 된 메소드 를 호출 할 수 있습니다 Any.

  f.toString

또는 메소드를 Function1[Int,Int]호출 하고 두 개의 다른 함수를 함께 연결 하여 다른 객체를 정의 할 수 있습니다.composef

 val f2 = f.compose((x:Int) => x - 1)

이제 실제로 함수를 실행하거나 수학자가 "인수에 함수 적용"이라고 말하면 객체 에서 apply메소드를 호출 Function1[Int,Int]합니다.

 f2.apply(2)

f.apply(args)객체로 표현 된 함수를 실행할 때마다 쓰는 것은 객체 지향 방식이지만 많은 정보를 추가하지 않고 코드에 많은 혼란을 줄 수 있으며 더 많은 표준 표기법을 사용할 수 있습니다. 로 f(args). Scala 컴파일러가 들어가서 f함수 객체에 대한 참조 가 있고 f (args)표현 된 함수에 인수를 적용하기 위해 쓸 때마다 컴파일러 f (args)는 객체 메소드 호출로 자동 확장 됩니다 f.apply (args).

스칼라의 모든 함수는 객체로 취급 될 수 있으며 다른 방식으로도 작동합니다. 모든 객체는 apply메소드 가있는 한 함수로 취급 될 수 있습니다 . 이러한 객체는 함수 표기법에서 사용할 수 있습니다.

// we will be able to use this object as a function, as well as an object
object Foo {
  var y = 5
  def apply (x: Int) = x + y
}


Foo (1) // using Foo object in function notation 

객체를 함수로 취급하려는 많은 사용 사례가 있습니다. 가장 일반적인 시나리오는 팩토리 패턴 입니다. 팩토리 메소드를 사용하여 코드에 혼란을 추가하는 대신 apply인수 세트에 이의를 제기하여 연관된 클래스의 새 인스턴스를 작성할 수 있습니다.

List(1,2,3) // same as List.apply(1,2,3) but less clutter, functional notation

// the way the factory method invocation would have looked
// in other languages with OO notation - needless clutter
List.instanceOf(1,2,3) 

따라서 apply메소드는 스칼라에서 함수와 객체 사이의 간격을 좁히는 편리한 방법입니다.


1
객체에 맞춤 변수 유형을 추가하는 방법 AFAIK 불가능합니다. 예를 들면 다음과 같습니다 class Average[YType](yZeroValue:YType). 이 클래스가 있습니다. 객체는 유형 매개 변수를 사용할 수 없으므로 객체에서 YType을 어떻게 전달합니까?
Adrian

스칼라의 유형은 일반적으로 인수를 기반으로 추론 할 수 있지만 그렇지 않은 경우 대괄호를 통해 입력 할 수 있습니다. 평균 개체를 인스턴스화 할 때 "val avg = new Average [Int] (0)"라고 말할 수 있습니다
Angelo Genovese

4
여기서 사례 클래스는 언급 할 가치가 있습니다. 케이스 클래스는 편리하게, 자동적으로 보이지 않게 추가 apply하고 unapply(다른 것들 사이) 클래스의 동반자 개체 방법. 따라서 이와 같이 한 줄로 클래스를 정의하면 다음과 같이 case class Car(make:String, model: String, year: Short, color: String)하여 Car 클래스의 새 객체를 생성 할 수 있습니다 val myCar = Car("VW","Golf",1999,"Blue"). 이를 위해 속기Car.apply(...)
Kjetil S.

1
every object can be treated as a function, provided it has the apply method-너무 많은 의미가 있습니다.
Arj


51

그것은 종종 물체에 무언가를 적용 하고 싶다는 생각에서 비롯 됩니다 . 더 정확한 예는 공장 중 하나입니다. 팩토리가있는 경우 매개 변수를 적용 하여 객체를 작성하려고합니다.

스칼라 녀석은 많은 상황에서 발생하기 때문에을 호출하는 지름길을 갖는 것이 좋을 것이라고 생각했습니다 apply. 따라서 매개 변수를 객체에 직접 제공하면 해당 매개 변수를 해당 객체의 apply 함수에 전달하는 것처럼 desugared됩니다.

class MyAdder(x: Int) {
  def apply(y: Int) = x + y
}

val adder = new MyAdder(2)
val result = adder(4) // equivalent to x.apply(4)

클래스 또는 특성에 대한 훌륭한 팩토리 메소드를 제공하기 위해 종종 동반자 객체에서 사용됩니다. 예는 다음과 같습니다.

trait A {
  val x: Int
  def myComplexStrategy: Int
}

object A {
  def apply(x: Int): A = new MyA(x)

  private class MyA(val x: Int) extends A {
    val myComplexStrategy = 42
  }
}

스칼라 표준 라이브러리에서 scala.collection.Seq구현 방법을 살펴볼 수 있습니다 Seq. 특성 new Seq(1, 2)은 컴파일되지 않지만 컴패니언 객체와 적용 덕분에 호출 할 수 Seq(1, 2)있으며 컴패니언 객체가 구현을 선택합니다.


Implicits를 사용하여 동등하게 적용 할 수 있습니까?
jayunit100

11

다음은 빠르게 숙달하려는 사람들을위한 작은 예입니다.

 object ApplyExample01 extends App {


  class Greeter1(var message: String) {
    println("A greeter-1 is being instantiated with message " + message)


  }

  class Greeter2 {


    def apply(message: String) = {
      println("A greeter-2 is being instantiated with message " + message)
    }
  }

  val g1: Greeter1 = new Greeter1("hello")
  val g2: Greeter2 = new Greeter2()

  g2("world")


} 

산출

인사 -1이 메시지 hello로 인스턴스화되고 있습니다.

greeter-2는 메시지 세계와 함께 인스턴스화되고 있습니다


2
g2에 대한 메시지가 정확합니까? 실제로 인스턴스화에서 발생합니까, 아니면 실제로 인스턴스화 후에 발생합니까 (게으른 인스턴스화 되더라도)?
팀 바라 스
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.