尝试使用类型参数编写DRY Scala代码

Oli*_*ain 3 inheritance scala traits case-class type-parameter

我已经定义了一些所有具有字段id的case类:Id [T],其中T是case类的类型.我想有一个特性强制执行此属性来编写这些类的通用代码.

我的第一次尝试在特征上使用类型参数和自我类型来强制执行此属性:

case class Id[M](value: Long)

trait EnforceIdType[T] {
  this: T =>
  val id: Id[T]
}

case class A(id: Id[A]) extends EnforceIdType[A]
case class B(id: Id[B]) extends EnforceIdType[B]
// case class C(id: Id[B]) extends EnforceIdType[B] < Won't compile, as expected
Run Code Online (Sandbox Code Playgroud)

这很好,但我想知道是否有一种方法可以在不使用特征上的类型参数的情况下做同样的事情.这是我的第二次尝试:

case class Id[M](value: Long)

trait EnforceIdType {
  val id: Id[_ <: EnforceIdType]
}

case class A(id: Id[A]) extends EnforceIdType
case class B(id: Id[B]) extends EnforceIdType
case class C(id: Id[B]) extends EnforceIdType // Compiles :(
Run Code Online (Sandbox Code Playgroud)

具体来说,我想使用案例类的这些定义(不将类型参数传递给EnforceIdType)但仍强制执行该属性(此C不应编译).有没有办法做到这一点?我觉得this.type这里可以使用的东西,但我不是很熟悉它.

Yur*_*riy 6

你是对的,this.type需要使用,但有一些限制:

trait EnforceIdType {
  def id: Id[_ >: this.type <: EnforceIdType]
}

case class A(id: Id[A]) extends EnforceIdType
case class B(id: Id[B]) extends EnforceIdType
//case class C(id: Id[B]) extends EnforceIdType // Won't compile, as expected
Run Code Online (Sandbox Code Playgroud)

更新:

关于第二个限制(由Alexey Romanov显示).它可以被消除,但有很长的路要走:

//Embeded polymorphism used
class Id(val value: Long) {
  type M
}

// Factory method for shift type variable to type parameter field
object Id {
  def apply[T](value : Long) = new Id(value) { type M = T }
}

trait EnforceIdType {
  type This = this.type // store this.type for use inside Id { type M = .. }
  val id: Id { type M >: This <: EnforceIdType } // need to be val

  def show(x : id.M) { println (x) } // dependent method
}

case class A(id: Id { type M = A }) extends EnforceIdType
case class B(id: Id { type M = B }) extends EnforceIdType
//  case class C(id: Id { type M = B }) extends EnforceIdType // Won't compile, as expected

val a = A( Id[A](10))
val b = B( Id[B](10))

a.show(a)
// a.show(b) // Won't compile, as expected
Run Code Online (Sandbox Code Playgroud)