通用界限,其中大部分都不清楚

时间:2013-09-11 15:10:41

标签: scala

学习Scala的通用界限有点复杂。我知道:

T : Tr - T的类型为Tr,表示它实现了特征 Tr

T <: SuperClass - TSuperClass

的子类

T :> ChildClass - TChildClass

的超类

但是,还有更多的运营商:

<%%>

=:=

<:<>:>

<%%>

<%<>%>

我读到了他们,但正如我所说,没有可理解的解释。你能说得更清楚吗?

1 个答案:

答案 0 :(得分:3)

我使用了一些类型约束:

  1. 最简单的是<:>:。这些是类型层次结构的简单边界。

    trait A
    trait B extends A
    trait C extends B
    

    然后是方法

    def doSomething[T >:C <:B](data:T)
    

    可以替换BC代替T

  2. 然后键入涉及向方法添加隐式参数的约束。

    def doSmth1[T: MyTypeInfo] (data:T)
    

    在编译期间被重写为

    def doSmth1[T] (data:T)(implicit ev: MyTypeInfo[T])
    

    def doSmth2[T <% SomeArbitratyType] (data:T)
    

    被重写为

    def doSmth2[T] (data:T)(implicit ev: T => SomeArbitratyType)
    

    如果在范围内存在适合隐式参数的实例,则可以调用这两个方法。如果没有适当的实例,则编译器会发出错误。

    视图范围(<%)需要隐式转换,将T转换为另一种类型的实例(SomeArbitratyType)。

    更强大的是使用“类型类”。在类型类实例中,可以放置许多可以处理类型T的有用方法。特别是,可以使用转换方法并获得与视图边界类似的结果。

    示例:

    trait MyTypeInfo[T] {
      def convertToString(data:T):String
    }
    def printlnAdv[T : MyTypeInfo](data:T) {
      val ev = implicitly[MyTypeInfo[T]]
      println(ev.convertToString(data))
    }
    

    在范围的某处,应该存在MyTypeInfo[T]类型的隐式值:

    implicit val doubleInfo = new MyTypeInfo[Double] {
      def convertToString(data:Double):String = data.toString
    }
    

    implicit def convertToString(data:T):String
    
    def printlnAdv[T <% String](data:T) {
      val conversionResult = data : String
      println(conversionResult)
    }
    

    在范围的某处应该有隐式函数:

    implicit def convertDoubleToString(data:Double):String = data.toString
    
  3. 下一个奇怪的符号是=:=<:<。这些用于希望确保类型具有某些属性的方法中。当然,如果您声明一个通用参数,那么让<:>:指定类型就足够了。但是,如何处理非通用参数的类型?例如,封闭类的泛型参数,或在另一种类型中定义的某种类型。符号在这里有帮助。

    trait MyAlmostUniversalTrait[T] {
      def mySpecialMethodJustForInts(data:T)(implicit ev:T =:= Int)
    }
    

    该特征可用于任何类型T。但只有在为Int实例化特征时才能调用该方法。

    <:<存在类似的用例。但是这里我们没有“等于”约束,而是“小于”(如T<: T2)。

    trait MyAlmostUniversalTrait[T] {
      def mySpecialMethod(data:T)(implicit ev:T <:< MyParentWithInterestingMethods)
    }
    

    同样,该方法只能调用MyParentWithInterestingMethods后代的类型。

  4. 然后<%<<%非常相似,但它的使用方式与<:<非常相似 - 当类型不是通用参数时,它作为隐式参数。它转换为T2

    trait MyAlmostUniversalTrait[T] {
      def mySpecialMethod(data:T)(implicit ev:T <%< String) {
        val s = data:String
        ...
      }
    }
    

    可以安全地忽略恕我直言<%<。人们可以简单地声明所需的转换函数:

    trait MyAlmostUniversalTrait[T] {
      def mySpecialMethod(data:T)(implicit ev:T => String) {
        val s = data:String
        ...
      }
    }