[SCALA] 자기 유형과 특성 서브 클래스의 차이점은 무엇입니까?
SCALA자기 유형과 특성 서브 클래스의 차이점은 무엇입니까?
형질 A에 대한 자체 유형 :
trait B
trait A { this: B => }
"A도 B를 확장하지 않는 구체적인 클래스로 혼합 될 수 없다"고 말했다.
한편, 다음과 같은 :
trait B
trait A extends B
"A에있는 (콘크리트 또는 추상) 클래스 혼합이 또한 B에 혼합 될 것이다"고 말했다.
이 두 문장은 같은 것을 의미하지 않는다? 셀프 형은 간단한 컴파일 타임 오류의 가능성을 만드는 데에만 봉사하는 것 같다.
나는 무엇을 놓치고?
해결법
-
==============================
1.그것은 주로 같은 케이크 패턴과 같이 의존성 주입에 사용됩니다. 케이크 패턴을 포함하여 스칼라의 의존성 주입의 다양한 형태를 포함하는 훌륭한 문서가 존재한다. 당신은 "케이크 패턴 및 스칼라을"구글 경우, 프리젠 테이션 및 동영상을 포함하여 많은 링크를 얻을 것이다. 지금, 여기에 또 다른 질문에 대한 링크입니다.
그것은 주로 같은 케이크 패턴과 같이 의존성 주입에 사용됩니다. 케이크 패턴을 포함하여 스칼라의 의존성 주입의 다양한 형태를 포함하는 훌륭한 문서가 존재한다. 당신은 "케이크 패턴 및 스칼라을"구글 경우, 프리젠 테이션 및 동영상을 포함하여 많은 링크를 얻을 것이다. 지금, 여기에 또 다른 질문에 대한 링크입니다.
이제, 자기 특성 및 유형을 연장 차이 것과 같이, 이것은 간단하다. 당신은 B가 확장 말할 경우, B는 자기 유형을 사용하면 자기 종류로 만든 두 개의 특정 요구 사항이 있습니다, B는 A를 필요로하는 A.입니다 :
다음 예를 고려하십시오
scala> trait User { def name: String } defined trait User scala> trait Tweeter { | user: User => | def tweet(msg: String) = println(s"$name: $msg") | } defined trait Tweeter scala> trait Wrong extends Tweeter { | def noCanDo = name | } <console>:9: error: illegal inheritance; self-type Wrong does not conform to Tweeter's selftype Tweeter with User trait Wrong extends Tweeter { ^ <console>:10: error: not found: value name def noCanDo = name ^
트위터는 사용자의 서브 클래스 인 경우, 에러가 없을 것이다. 위의 코드에서, 우리는하지만 사용자가 잘못된에게 제공되지 않은, 트위터가 사용될 때마다 사용자 요구, 그래서 우리는 오류를 얻었다. 지금, 여전히 범위에서 위의 코드로, 고려 :
scala> trait DummyUser extends User { | override def name: String = "foo" | } defined trait DummyUser scala> trait Right extends Tweeter with User { | val canDo = name | } defined trait Right scala> trait RightAgain extends Tweeter with DummyUser { | val canDo = name | } defined trait RightAgain
오른쪽으로, 요구 사항은 혼합-에 대한 사용자 만족입니다. 그러나, 위에서 언급 한 두 번째 요구 사항은 만족하지 : 사용자를 구현하는 부담이 여전히 클래스 / 오른쪽 확장 형질 남아있다.
RightAgain으로 모두 요구 사항을 만족하고 있습니다. 사용자와 사용자의 구현이 제공됩니다.
더 실제 사용 사례를 들어,이 답변의 시작의 링크를 참조하시기 바랍니다! 그러나, 잘하면 지금 당신은 그것을 얻을.
-
==============================
2.셀프 유형은 순환 종속성을 정의 할 수 있습니다. 예를 들어, 당신이 이것을 달성 할 수있다 :
셀프 유형은 순환 종속성을 정의 할 수 있습니다. 예를 들어, 당신이 이것을 달성 할 수있다 :
trait A { self: B => } trait B { self: A => }
상속이 허용하지 않습니다 연장 사용. 시험:
trait A extends B trait B extends A error: illegal cyclic reference involving trait A
Odersky 책, 그것은 언급 섹션 33.5 (스프레드 시트 UI 장을 만들기)를 보면 :
package org.stairwaybook.scells trait Evaluator { this: Model => ...
도움이 되었기를 바랍니다.
-
==============================
3.하나의 추가 차이점은 자기 타입이 아닌 클래스 유형을 지정할 수 있다는 것입니다. 예를 들면
하나의 추가 차이점은 자기 타입이 아닌 클래스 유형을 지정할 수 있다는 것입니다. 예를 들면
trait Foo{ this: { def close:Unit} => ... }
여기에 자기 유형은 구조 유형입니다. 효과는 인수 없음 "가까운"방법은 반환하지 장치를 구현해야합니다 푸에 혼합이 아무 말도하는 것입니다. 이 오리 타이핑 안전 유지 mixin 수 있습니다.
-
==============================
4.실제로 아주 잘 믹스 인 구성을 넘어 selftype의 목적을 설명 마틴 오더 스키의 원래 스칼라 용지 확장 구성 요소 추상화의 "Selftype 주석"2.3 절 : 추상적 인 유형의 클래스를 연결하는 다른 방법을 제공합니다.
실제로 아주 잘 믹스 인 구성을 넘어 selftype의 목적을 설명 마틴 오더 스키의 원래 스칼라 용지 확장 구성 요소 추상화의 "Selftype 주석"2.3 절 : 추상적 인 유형의 클래스를 연결하는 다른 방법을 제공합니다.
신문에 주어진 예는 다음과 같았다, 그리고 우아한 서브 클래스 특파원을하지 않는 것 같습니다 :
abstract class Graph { type Node <: BaseNode; class BaseNode { self: Node => def connectWith(n: Node): Edge = new Edge(self, n); } class Edge(from: Node, to: Node) { def source() = from; def target() = to; } } class LabeledGraph extends Graph { class Node(label: String) extends BaseNode { def getLabel: String = label; def self: Node = this; } }
-
==============================
5.자기 유형은 당신이 철저하게 밀봉 된 계층 구조에 대해 일치, 특히 그들이 패턴 매칭에서 제외 할 수 있습니다 필요한 클래스의 계층 구조의 일부가 아닌 이유는 언급되지 않은 또 다른 것은. 이 같은 직교 행동을 모델링 할 때 편리합니다 :
자기 유형은 당신이 철저하게 밀봉 된 계층 구조에 대해 일치, 특히 그들이 패턴 매칭에서 제외 할 수 있습니다 필요한 클래스의 계층 구조의 일부가 아닌 이유는 언급되지 않은 또 다른 것은. 이 같은 직교 행동을 모델링 할 때 편리합니다 :
sealed trait Person trait Student extends Person trait Teacher extends Person trait Adult { this : Person => } // orthogonal to its condition val p : Person = new Student {} p match { case s : Student => println("a student") case t : Teacher => println("a teacher") } // that's it we're exhaustive
-
==============================
6.TL; 다른 답변의 DR 요약 :
TL; 다른 답변의 DR 요약 :
-
==============================
7.의는 순환 종속성을 시작하자.
의는 순환 종속성을 시작하자.
trait A { selfA: B => def fa: Int } trait B { selfB: A => def fb: String }
그러나,이 솔루션의 모듈화는 당신이 그렇게로 자기 유형을 대체 할 수 있기 때문에 먼저 나타날 수만큼 큰되지 않습니다 :
trait A1 extends A { selfA1: B => override def fb = "B's String" } trait B1 extends B { selfB1: A => override def fa = "A's String" } val myObj = new A1 with B1
하지만 당신이 자기 형의 멤버를 오버라이드 (override)하는 경우, 당신은 여전히 상속을 사용하여 슈퍼를 통해 액세스 할 수있는 원래의 멤버에 대한 액세스를 잃게됩니다. 그래서 정말 상속을 사용을 통해 얻게되는 것은 :
trait AB { def fa: String def fb: String } trait A1 extends AB { override def fa = "A's String" } trait B1 extends AB { override def fb = "B's String" } val myObj = new A1 with B1
지금은 케이크 패턴의 모든 미묘함을 이해하고 주장 할 수 있지만, 모듈화 시행의 주요 방법은 구성보다는 상속 또는 자체 유형을 통해 저를 친다.
상속 버전은 짧은,하지만 난 자기 유형을 통해 상속을 선호하는 주된 이유는 내가 훨씬 더 까다로운 자기 유형과 올바른 초기화 순서를 얻을 찾을 수 있다는 것입니다. 그러나, 당신은 당신이 상속 할 수없는 자기 유형과 할 수있는 몇 가지가있다. 상속은 특성 또는 같은 클래스를 필요로하면서 자기 유형은 유형을 사용할 수 있습니다 :
trait Outer { type T1 } trait S1 { selfS1: Outer#T1 => } //Not possible with inheritance.
당신은 할 수 있습니다 :
trait TypeBuster { this: Int with String => }
당신은 그것을 인스턴스화 할 수 없을거야하지만. 나는 형식에서 상속 할 수없는 대한 절대적인 이유가 없지만, 나는 확실히 우리가 타입 생성자 특성 / 클래스를 가지고 경로 생성자 클래스와 특성을 가지고 도움이 될 것입니다 생각합니다. 불행하게도
trait InnerA extends Outer#Inner //Doesn't compile
우리는이있다 :
trait Outer { trait Inner } trait OuterA extends Outer { trait InnerA extends Inner } trait OuterB extends Outer { trait InnerB extends Inner } trait OuterFinal extends OuterA with OuterB { val myV = new InnerA with InnerB }
아니면 이거:
trait Outer { trait Inner } trait InnerA {this: Outer#Inner =>} trait InnerB {this: Outer#Inner =>} trait OuterFinal extends Outer { val myVal = new InnerA with InnerB with Inner }
더 empathised해야 한 점은 특성 수있는 클래스를 확장한다는 것이다. 이 문제를 지적 데이비드 Maclver 감사합니다. 여기에 내 자신의 코드에서 예입니다 :
class ScnBase extends Frame abstract class ScnVista[GT <: GeomBase[_ <: TypesD]](geomRI: GT) extends ScnBase with DescripHolder[GT] ) { val geomR = geomRI } trait EditScn[GT <: GeomBase[_ <: ScenTypes]] extends ScnVista[GT] trait ScnVistaCyl[GT <: GeomBase[_ <: ScenTypes]] extends ScnVista[GT]
ScnBase는 스윙 프레임 클래스에서 상속, 그래서 자기 유형으로 사용하고 (인스턴스에서) 마지막에 혼합 할 수있다. 그러나, 발 geomR는이 특성을 상속에 의해 사용되기 전에 초기화해야합니다. 그래서 우리는 geomR의 사전 초기화를 시행하는 클래스가 필요합니다. 클래스 ScnVista은 다음 자체에서 상속 할 수있는 여러 직교 특성에 의해 상속 될 수있다. 여러 유형 매개 변수 (제네릭)을 사용하여 모듈 방식의 대안 양식을 제공합니다.
-
==============================
8.
trait A { def x = 1 } trait B extends A { override def x = super.x * 5 } trait C1 extends B { override def x = 2 } trait C2 extends A { this: B => override def x = 2} // 1. println((new C1 with B).x) // 2 println((new C2 with B).x) // 10 // 2. trait X { type SomeA <: A trait Inner1 { this: SomeA => } // compiles ok trait Inner2 extends SomeA {} // doesn't compile }
-
==============================
9.자체 유형은이 특성을 믹스 인 할 수 있습니다 어떤 종류를 지정할 수 있습니다. 당신이 닫기 가능한 자체 유형의 특성이있는 경우 예를 들어, 그 특성은 그것을에서 혼합 할 수있는 유일한 일이의 닫기 가능한 인터페이스를 구현해야한다는 것을 알고있다.
자체 유형은이 특성을 믹스 인 할 수 있습니다 어떤 종류를 지정할 수 있습니다. 당신이 닫기 가능한 자체 유형의 특성이있는 경우 예를 들어, 그 특성은 그것을에서 혼합 할 수있는 유일한 일이의 닫기 가능한 인터페이스를 구현해야한다는 것을 알고있다.
-
==============================
10.업데이트 : 주체 차이가 자기 타입이 여러 클래스에 따라 달라질 수 있다는 점이다 (나는 조금 코너 케이스 것 인정). 예를 들어, 당신은 할 수 있습니다
업데이트 : 주체 차이가 자기 타입이 여러 클래스에 따라 달라질 수 있다는 점이다 (나는 조금 코너 케이스 것 인정). 예를 들어, 당신은 할 수 있습니다
class Person { //... def name: String = "..."; } class Expense { def cost: Int = 123; } trait Employee { this: Person with Expense => // ... def roomNo: Int; def officeLabel: String = name + "/" + roomNo; }
이것은 단지 사람과 비용의 서브 클래스입니다 아무것도 직원 믹스 인을 추가 할 수 있습니다. 비용은 한 사람 또는 그 반대를 확장하는 경우 물론,이 경우에만 의미가 있습니다. 요점은 자기 유형의 직원을 사용하는가에 따라 클래스의 계층 구조에 독립적이 될 수 있다는 것입니다. 그것은 무엇을 확장 무슨 상관하지 않는다 - 당신은 사람 대 비용의 계층 구조를 전환하면, 당신은 직원을 수정할 필요가 없습니다.
-
==============================
11.첫 번째의 경우, B의 하위 특성 또는 서브 클래스 B는 추상적 인 특성이 될 수 있도록 어떤 A. 사용하여 혼합 될 수있다.
첫 번째의 경우, B의 하위 특성 또는 서브 클래스 B는 추상적 인 특성이 될 수 있도록 어떤 A. 사용하여 혼합 될 수있다.
from https://stackoverflow.com/questions/1990948/what-is-the-difference-between-self-types-and-trait-subclasses by cc-by-sa and MIT license
'SCALA' 카테고리의 다른 글
[SCALA] 스칼라의 수율은 무엇입니까? (0) | 2019.10.29 |
---|---|
[SCALA] 왜 예는 컴파일되지 않습니다 (공동, 콘트라 및 IN-) 분산 작업을 수행 일명 어떻게? (0) | 2019.10.29 |
[SCALA] 스칼라 : 어떤 TypeTag이고 내가 그것을 어떻게 사용합니까? (0) | 2019.10.28 |
[SCALA] 중괄호와 괄호 사이 스칼라의 공식 차이는 무엇, 그리고 때 사용해야인가? (0) | 2019.10.28 |
[SCALA] 무엇`을 수행합니다 _ *`(콜론 스타 밑줄) 스칼라합니까? (0) | 2019.10.28 |