-->

为什么这是一个无效的使用Scala的抽象类型的?(Why is this an invalid us

2019-10-20 14:00发布

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.

Answer 1:

您的代码必须看起来像:

// --- 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型参数定义XY

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


Answer 2:

我想你要实现的目标是这样的:

//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]
}

你有完全类型安全的同一水平。



文章来源: Why is this an invalid use of Scala's abstract types?