스칼라에서 'type'키워드의 기능 이해


144

나는 스칼라를 처음 접했고 type키워드 에 대해 많이 찾을 수 없었습니다 . 다음 표현의 의미를 이해하려고합니다.

type FunctorType = (LocalDate, HolidayCalendar, Int, Boolean) => LocalDate

FunctorType 일종의 별칭이지만 무엇을 의미합니까?

답변:


148

예, 타입 별칭 FunctorType 은 속기입니다.

(LocalDate, HolidayCalendar, Int, Boolean) => LocalDate

타입 별칭은 종종 나머지 코드를 단순하게 유지하는 데 사용됩니다.

def doSomeThing(f: FunctorType)

컴파일러는 다음과 같이 해석합니다.

def doSomeThing(f: (LocalDate, HolidayCalendar, Int, Boolean) => LocalDate)

예를 들어 다른 유형에 정의 된 튜플 또는 함수 인 많은 사용자 정의 유형을 정의하지 않아도됩니다.

몇 가지 흥미로운 사용 사례가있다 type, 예를 들어 설명한 바와 같이, 이 장스칼라 프로그래밍 .


198

실제로 typeScala 의 키워드는 복잡한 유형을 더 짧은 이름으로 별칭 지정하는 것 이상의 기능을 수행 할 수 있습니다. 타입 멤버를 소개 합니다 .

아시다시피 클래스에는 필드 멤버와 메서드 멤버가있을 수 있습니다. 스칼라는 클래스에 타입 멤버를 가질 수도 있습니다.

특별한 경우 type 더 간결한 코드를 작성할 수있는 별명을 도입하는 것입니다. 타입 시스템은 타입 검사가 수행 될 때 별칭을 실제 타입으로 대체합니다.

그러나 당신은 또한 이와 같은 것을 가질 수 있습니다

trait Base {
  type T

  def method: T
}

class Implementation extends Base {
  type T = Int

  def method: T = 42
}

클래스의 다른 멤버와 마찬가지로 형식 멤버도 추상적 일 수 있으며 (실제로 값을 지정하지 않아도 됨) 구현에서 재정의 될 수 있습니다.

제네릭으로 구현할 수있는 많은 것들이 추상적 인 타입 멤버로 변환 될 수 있기 때문에 타입 멤버는 제네릭의 이중으로 볼 수 있습니다.

따라서 예를 들어 앨리어싱에 사용할 수 있지만 스칼라 유형 시스템의 강력한 기능이기 때문에 이것으로 제한하지 마십시오.

자세한 내용은이 훌륭한 답변을 참조하십시오.

스칼라 : 추상 타입과 제네릭


44
클래스 내에서 형식을 사용하면 별칭 대신 형식 멤버가 만들어집니다. 따라서 유형 별명 만 필요한 경우 컴패니언 오브젝트에서이를 정의하십시오.
Rüdiger Klaehn

9

Roland Ewald 의 답변은 별명 유형 별칭의 매우 간단한 유스 케이스로 설명했기 때문에 더 좋았습니다. 자세한 내용은 매우 훌륭한 자습서를 소개했습니다. 또 다른 사용 사례의 이름이 게시물에 도입되어 있기 때문에, 형식 멤버 , 내가 매우 좋아 그것의 대부분의 실제 사용 사례, 언급하고 싶습니다 (이 부분에서 가져옵니다 여기를 :)

추상 유형 :

type T

위의 T는 사용될 유형이 아직 알려지지 않았으며 구체적인 서브 클래스에 따라 정의 될 것이라고합니다. 프로그래밍 개념을 항상 이해하는 가장 좋은 방법은 예를 제공하는 것입니다. 다음 시나리오가 있다고 가정합니다.

타입 추상화없이

Cow 및 Tiger 클래스의 eat 메소드는 매개 변수 유형이 다르기 때문에 Animal 클래스의 eat 메소드를 대체하지 않기 때문에 컴파일 오류가 발생합니다. Cow 클래스의 Grass, Tiger 클래스의 Meat vs. Super 클래스 인 Animal 클래스의 Food는 모든 하위 클래스를 준수해야합니다.

이제 다음 다이어그램을 통해 유형 추상화로 돌아가서 단순히 유형 추상화를 추가하면 서브 클래스 자체에 따라 입력 유형을 정의 할 수 있습니다.

추상적 인 유형으로

이제 다음 코드를 살펴보십시오.

  val cow1: Cow = new Cow
  val cow2: Cow = new Cow

  cow1 eat new cow1.SuitableFood
  cow2 eat new cow1.SuitableFood

  val tiger: Tiger = new Tiger
  cow1 eat new tiger.SuitableFood // Compiler error

컴파일러는 행복하고 디자인을 향상시킵니다. 젖소에게 젖소에게 먹이를 줄 수 있습니다. 적당한 음식과 컴파일러는 호랑이에게 적합한 음식으로 젖소를 먹이지 못하게합니다. 그러나 cow1의 적합한 음식과 cow2의 SuitabeFood의 차이를 만들고 싶다면 어떨까요? 다시 말해서, 우리가 유형에 도달하는 경로가 (물론 객체를 통해) 기본적으로 중요하다면 일부 시나리오에서 매우 편리합니다. 스칼라의 고급 기능 덕분에 가능합니다.

경로 종속 유형 : 스칼라 객체는 유형을 멤버로 가질 수 있습니다. 유형의 의미는 액세스하는 경로에 따라 다릅니다. 경로는 객체 (일명 클래스의 인스턴스)에 대한 참조에 의해 결정됩니다. 이 시나리오를 구현하려면 Cow 내부에 Grass 클래스를 정의해야합니다. 즉, Cow는 외부 클래스이고 Grass는 내부 클래스입니다. 구조는 다음과 같습니다.

  class Cow extends Animal {
    class Grass extends Food
    type SuitableFood = Grass
    override def eat(food: this.SuitableFood): Unit = {}
  }

  class Tiger extends Animal {
    class Meat extends Food
    type SuitableFood = Meat
    override def eat(food: this.SuitableFood): Unit = {}
  }

이 코드를 컴파일하려고하면 :

  1. val cow1: Cow = new Cow
  2. val cow2: Cow = new Cow

  3. cow1 eat new cow1.SuitableFood
  4. cow2 eat new cow1.SuitableFood // compilation error

4 행에서 Grass는 이제 Cow의 내부 클래스이기 때문에 오류가 표시되므로 Grass의 인스턴스를 만들려면 cow 객체가 필요하며이 cow 객체는 경로를 결정합니다. 따라서 2 개의 소 물체는 2 개의 다른 경로를 발생시킵니다. 이 시나리오에서 cow2는 특별히 만들어진 음식 만 먹고 싶어합니다. 그래서:

cow2 eat new cow2.SuitableFood

이제 모두가 행복합니다 :-)


5

별명으로 "type"을 사용하는 방법을 보여주는 예제입니다.

type Action = () => Unit

위의 정의는 Action을 빈 매개 변수 목록을 가져와 Unit을 반환하는 프로 시저 (메소드) 유형의 별칭으로 정의합니다.

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