什么是Scala<:<,=:=和<%<上课?

时间:2011-08-04 21:01:24

标签: scala

  

可能重复:
  What do <:<, <%<, and =:= mean in Scala 2.8, and where are they documented?

我很好奇,因为我在Scala库代码中看到了它们,但我发现谷歌很难对它们说些什么,因为它们的名字不是单词。

3 个答案:

答案 0 :(得分:10)

这些类用于限制方法适用性的隐式参数。以下是每个班级的说明。通常,它们可用于在单个方法的上下文中约束封闭类的类型参数。

<:<[A,B]A <:< B

只有当A是B的子类型时,编译器才能提供此类型的隐式实例。这类似于类型参数列表中的A <: B

当您希望在特定方法的上下文中对类类型参数添加其他约束时,这可能很有用。例如,下面的Foo类可以用于任何类型,但方法bar仅在TNumber的子类型时才有效。

class Foo[T](x: T) {
  // In general T could be any type
  def bar(implicit ev: T <:< Number) = {
    // This method can now only be used when T is a subtype of Number
    // also, you can use ev to convert a T to number
    ev(x).doubleValue
  }
}

new Foo(123 : java.lang.Integer).bar // returns 123.0: Double
new Foo("123").bar // compile error: Cannot prove java.lang.String <:< java.lang.Number

=:=[A,B]A =:= B

只有当A与B的类型相同时,编译器才能提供此类型的隐式实例。这在类型参数列表中没有等效语法,您只需使用相同的类型参数两次。

这可以像<:<一样使用,除了它要求类型完全匹配。这可以用来使一对方法相互排斥。

class Foo[T<:Number](x:T) {
  def numOnly(implicit ev: T =:= Number) = ()
  def floatOnly(implicit ev: T =:= Float) = ()
}

val asFloat = new Foo(123.0f:java.lang.Float)
asFloat.numOnly // Compile error
asFloat.floatOnly // Ok
val asNum = new Foo(123.0f:java.lang.Number)
asFloat.floatOnly // Ok
asFloat.numOnly // Compile error

基本上,如果type参数比约束更具体,你可以强制使用更具体的方法。

<%<[A,B]A <%< B

只有当A可以转换为B时,编译器才能提供此类型的隐式实例。这类似于类型参数列表中的A <% B

这要求有一个隐式函数可用于将A转换为B.这在A <: B时始终是可能的,因为隐式A <:< B满足此约束。

此类实际上已标记为已弃用。它说你应该只使用A => B

答案 1 :(得分:4)

<:<=:=<%<是泛型类,它们都有两个类型参数,所有这些都扩展了Function1(带有一个参数的函数)。它们在Predef中定义。 它们旨在提供非常基本的转换作为含义。转换是如此基本,大多数时候,它们是身份。拥有这些类而不是函数的关键在于它们可以与可能在隐式范围内的其他函数区分开来。 Predef提供以下隐式

  • 对于每种类型A,都可以使用<:<[A,A]<:<[-From, +To]<:<[A,A]会满足<:<[A,B]符合A的所有B。该 实施是身份。
  • 对于每种类型A,还有一个=:=[A,A],但=:=是不变的, 如果A不完全是B.它不会满足任何A =:= B 实施是身份
  • 每次A <%< B还有一个A <% B。实施是 A <% B隐含的隐式转化。

重点不在于提供巧妙的转换(身份不是太聪明),而是提供库级方式在编译时强制执行某些类型约束,类似于语言级别约束&lt;:,&lt;%,以及简单缺乏在语言约束不可用的地方,类型参数(也是一个非常强的约束)。一个典型的例子是,在泛型类中,当您希望方法仅可用于某个类型参数的值时。假设收集[A],我想要一个方法排序,只有在A&lt ;:Ordered [A]时才可用。我不想将约束放在类的声明中,因为我想接受其元素不是Ordered的集合。我只是不希望他们有sort方法。我也不能将约束放在方法sort上,因为A甚至不会显示为方法排序的类型参数。 &LT;:其中提供解决方案:

class MyCollection[A] {
    def sort(implicit ev: A <:< Ordered[A])
    // other methods, without constraints
}

这样做,sort在技术上可用于MyCollection的所有实例,但实际上,如果没有明确地传递ev参数,它将在隐式范围内查找A <:< Ordered[A],并在predef中查找conforms仅当AOrdered[A]的子类型时才会给出一个。由于AOrdered[A]之间的(标识)转换在例程的隐式范围内可用,A将在方法排序主体中用作an Ordered[A]

使用=:=会强制类型被精确地排序[A](MyCollection上的等效约束只是为了使它不是通用的,并且将给定的类型放在任何地方都有泛型参数)。 <%<将确保隐式转换。那将是更有可能在这里。

实际上,对于这种特定的方法排序,正确的解决方案是在隐式上下文中使用Ordering[A]获得def sort(implicit ev: Ordering[A]),但这不会证明这些类的重点。

答案 2 :(得分:1)

它们是类型参数的通用类型约束。查看它们的定义以及Predef中相应的隐式conforms()方法。

简而言之,它的工作原理如下:

  • 您向方法添加隐式参数,例如implicit tc: T <:< U,其作用类似于implicit tc: <:<[T, U]
  • implicit conforms()方法返回必需的实例,确保T <: U(就像常规泛型一样)
  • 如果T <: U不是这种情况,方法调用的编译将失败并显示“隐式未找到”

在此处查看用法示例:http://java.dzone.com/articles/using-generalized-type

相关问题