I have this code:
class A extends Testable { type Self <: A }
class B extends A { type Self <: B }
trait Testable {
type Self
def test[T <: Self] = {}
}
object Main {
val h = new A
// this throws an error
h.test[B]
}
And my error is:
error: type arguments [B] do not conform to method test's type parameter bounds [T <: Main.h.Self]
h.test[B]
On this question, it was said that this was due to path dependent types. Can anyone figure out how to have T <: Self, without having the path-dependent types problem?
Any help would be appreciated.
您的代码必须看起来像:
// --- fictional scala syntax ---
class A extends Testable { type Self = A }
class B extends A { override type Self = B }
但它是Scala中的当前版本IMPOSIBLE。
我建议有点很长的路要走(不超过使用路径依赖的类型,但是另一个更长),并且它符合您的要求。
a)用于试验方法中的用途类型类模式;
b)利用对符合型关系隐含参数。
类层次结构:
trait Testable
class A extends Testable
class B extends A
符合特质:
trait Conforms[X, Y]
可测试的类型类:
object TestableTypeClass {
implicit def testMethod[T <: Testable](testable : T) = new {
def test[X](implicit ev : Conforms[X, T]) = {}
}
}
test
方法类型参数条件在同伴对象:
object A {
// P <: A is your conditon (Self <: A) for class A
implicit def r[P <: A] = new Conforms[P , A] {}
}
object B {
// P <: B is your conditon (Self <: B) for class B
implicit def r[P <: B] = new Conforms[P , B] {}
}
测试:
import TestableTypeClass._
val a = new A
a.test[A] // - Ok
a.test[B] // - Ok
val b = new B
// b.test[A] // - did not compile
b.test[B] // - Ok
更新:
1)它可以收集所有implicits在一个对象,在这种情况下物体implicits需要进口(不是由同伴对象隐含范围的规则之前,需要它):
object ImplicitContainer {
implicit def r1[P <: A] = new Conforms[P , A] {}
implicit def r2[P <: B] = new Conforms[P , B] {}
}
使用:
import TestableTypeClass._
import ImplicitContainer._
val a = new A
a.test[A]
a.test[B]
2,3)性状Conforms
2型参数定义X
& Y
X - 用于将来的类型约束(这约束来自参数方法)
ÿ - 用于确定类型为这将是限定类型约束
隐含参数的choise通过Comforms
实例类型,而这种设计理念是玩组合X&Y
在类型级TestableTypeClass
Y型从捕获由隐式转换Testable
与anonimous类test
方法,并且在X型捕获test
方法调用。
而一个主要特点是不变性Conforms
特征,这就是为什么implicits一点也不含糊,并正确地管理约束规则。
而为了更好的理解,一个例子具有更严格的规则:
//...
class C extends B
object ImplicitContainer {
implicit def r1[P <: A] = new Conforms[P , A] {}
implicit def r2[P](implicit ev : P =:= B) = new Conforms[P , B] {}
implicit def r3[P <: C] = new Conforms[P , C] {}
}
import TestableTypeClass._
import ImplicitContainer._
val b = new B
//b.test[A] // - did not compile
b.test[B] // - Ok
//b.test[C] // - did not compile
我想你要实现的目标是这样的:
//this is of course not a correct Scala code
def test[T <: upperBoundOf[Self]]
但是,这没有任何意义。 为什么? 因为你可以很容易规避这样的约束,有效地使其毫无意义:
val h = new B
h.test[A] //nope, A is not a subtype of B
但...
val h: A = new B
h.test[A] //same thing, but this time it's apparently OK
不仅约束提供零附加类型的安全性,我想这也导致破损OOP的最基本的规则之一- 里氏替换原则 。 当片段上方编译h
的类型是A
但当不编译h
的类型是B
,即使它的一个亚型A
,所以一切应根据LSP被罚款。
所以,基本上,如果你只是离开你的类型是这样的:
class A extends Testable
class B extends A
trait Testable {
def test[T <: A]
}
你有完全类型安全的同一水平。