[SCALA] 어떻게 자기 형을 구현하는 등 스칼라의이 입력, 추상적 인 유형을 사용 하는가?
SCALA어떻게 자기 형을 구현하는 등 스칼라의이 입력, 추상적 인 유형을 사용 하는가?
나는 다른 질문이에 대한 답을 찾을 수 없습니다. 나는 두 개의 서브 클래스, 1 콘크리트와 콘크리트 1과 추상 슈퍼 클래스 Abstract0을 가지고 있다고 가정하자. 내가 좋아하는 Abstract0 무언가를 정의 할 수있게하려면
def setOption(...): Self = {...}
어디 자체는 콘크리트 하위 유형이 될 것입니다. 이 같은에서 SetOption 호출 체인 허용합니다 :
val obj = new Concrete1.setOption(...).setOption(...)
여전히 OBJ의 추론 유형으로 1 콘크리트를 얻을.
내가 원하지 않는 것은이 정의하는 것입니다 :
abstract class Abstract0[T <: Abstract0[T]]
어렵게 클라이언트가이 유형을 처리하기 위해 그것을하게하기 때문이다. 나는 추상 형식 등 다양한 가능성을 시도했다 :
abstract class Abstract0 {
type Self <: Abstract0
}
class Concrete1 extends Abstract0 {
type Self = Concrete1
}
하지만 Abstract0이 유형 자체가 없기 때문에,에서 SetOption을 구현하는 것은 불가능합니다. 그리고이 사용 : 자기를 => 또한 Abstract0에 일을하지 않습니다.
이 문제에 어떤 해결책이 있습니까?
해결법
-
==============================
1.이 this.type가 무엇인지입니다 :
이 this.type가 무엇인지입니다 :
scala> abstract class Abstract0 { | def setOption(j: Int): this.type | } defined class Abstract0 scala> class Concrete0 extends Abstract0 { | var i: Int = 0 | def setOption(j: Int) = {i = j; this} | } defined class Concrete0 scala> (new Concrete0).setOption(1).setOption(1) res72: Concrete0 = Concrete0@a50ea1
당신이에서 SetOption 반환을 볼 수 있듯이 실제의 형태는, Abstract0하지 사용. Concrete0 다음 setOtherOption이 있다면 (새 Concrete0는) .setOption (1) .setOtherOption (...) 일 것
업데이트 : 어떻게 새로운 인스턴스를 반환하는 주석 (에 JPP의 후속 질문에 대답하려면 : 질문에 설명 된 일반적인 접근은 (추상 유형을 사용하여) 권리입니다. 그러나 새 인스턴스 요구의 생성은 각 서브 클래스에 명시 될 수 있습니다.
한 가지 방법은 다음과 같습니다
abstract class Abstract0 { type Self <: Abstract0 var i = 0 def copy(i: Int) : Self def setOption(j: Int): Self = copy(j) } class Concrete0(i: Int) extends Abstract0 { type Self = Concrete0 def copy(i: Int) = new Concrete0(i) }
또 다른 하나는 스칼라의 수집 라이브러리에 사용되는 빌더 패턴을 따르는 것입니다. 즉에서 SetOption는 암시 빌더 파라미터를 수신한다. 이 새로운 인스턴스를 구축하는 것은 단지 '사본'보다 더 많은 방법으로 수행 할 수 있다는 장점을 가지고 복잡한 수행 할 수 있습니다 빌드 것을. 예를 들면 setSpecialOption은 반환 인스턴스가 SpecialConcrete해야 지정할 수 있습니다.
여기에 솔루션의 그림입니다 :
trait Abstract0Builder[To] { def setOption(j: Int) def result: To } trait CanBuildAbstract0[From, To] { def apply(from: From): Abstract0Builder[To] } abstract class Abstract0 { type Self <: Abstract0 def self = this.asInstanceOf[Self] def setOption[To <: Abstract0](j: Int)(implicit cbf: CanBuildAbstract0[Self, To]): To = { val builder = cbf(self) builder.setOption(j) builder.result } } class Concrete0(i: Int) extends Abstract0 { type Self = Concrete0 } object Concrete0 { implicit def cbf = new CanBuildAbstract0[Concrete0, Concrete0] { def apply(from: Concrete0) = new Abstract0Builder[Concrete0] { var i = 0 def setOption(j: Int) = i = j def result = new Concrete0(i) } } } object Main { def main(args: Array[String]) { val c = new Concrete0(0).setOption(1) println("c is " + c.getClass) } }
업데이트 2 : JPP의 두 번째 주석에 응답. 중첩 여러 수준의 경우, 형식 멤버 대신 형식 매개 변수를 사용하고 특성에 Abstract0합니다
trait Abstract0[+Self <: Abstract0[_]] { // ... } class Concrete0 extends Abstract0[Concrete0] { // .... } class RefinedConcrete0 extends Concrete0 with Abstract0[RefinedConcrete0] { // .... }
-
==============================
2.이 this.type의 정확한 사용 사례입니다. 그것은 같은 것이다 :
이 this.type의 정확한 사용 사례입니다. 그것은 같은 것이다 :
def setOption(...): this.type = { // Do stuff ... this }
from https://stackoverflow.com/questions/4313139/how-to-use-scalas-this-typing-abstract-types-etc-to-implement-a-self-type by cc-by-sa and MIT license
'SCALA' 카테고리의 다른 글
[SCALA] 스칼라의 '::'연산자, 어떻게 작동합니까? (0) | 2019.11.06 |
---|---|
[SCALA] 동적 특성에 혼합 (0) | 2019.11.06 |
[SCALA] 어떻게 추가 "제공"종속성 / 테스트 작업 '클래스 경로를 실행하는 백업? (0) | 2019.11.06 |
[SCALA] 스칼라에서 유효한 식별자 문자 (0) | 2019.11.06 |
[SCALA] 다중 스칼라 형 패턴 매칭 (0) | 2019.11.06 |