scala:执行输入转换时从类型T到类型T的泛型函数

时间:2017-06-19 12:00:21

标签: scala pattern-matching typeclass

我有以下非常设计的例子:

def f[T](t: T): T = {
  t match {
    case a : Int => a * 2
    case _ => t
  }
}

// Exiting paste mode, now interpreting.

<console>:14: error: type mismatch;
 found   : Int
 required: T
           case a : Int => a * 2
                             ^

我的问题是:

  1. 为什么编译器不将IntT
  2. 进行协调
  3. 除了转换为(a * 2).asInstanceOf[T]之外还有其他策略可以操作多态返回相同类型的实例的事情,而对T没有什么特别的了解吗? (保存类型类?)
  4. 请注意以下类型类实现,甚至不那么优雅:

    trait Manipulator[A] {
      def manip(a: A): A
    }
    
    implicit object IntManip extends Manipulator[Int] {
      override def manip(a: Int): Int = a * 2
    }
    
    implicit object WhateverManip extends Manipulator[Any] {
      override def manip(a: Any): Any = a
    }
    def g[T](t: T)(implicit manipulator: Manipulator[T]) = {
      manipulator.manip(t)
    }
    
    g(2)
    
    g(2.3.asInstanceOf[Any])(WhateverManip)
    

    我本可以取消asInstanceOf[Any]Manipulator逆变,但......:

    trait Manipulator[-A] {
      def manip(a: A): A
    }
    
    // Exiting paste mode, now interpreting.
    
    <console>:13: error: contravariant type A occurs in covariant position in type (a: A)A of method manip
             def manip(a: A): A
    

1 个答案:

答案 0 :(得分:2)

  1. 启用文字类型后,您可以拨打f[3](3)。没有文字类型,在标准,当前,无选项Scala中,您仍然可以val a = new Integer(3); f[a.type](a)。如果将类型参数T修复为3,则表示返回类型也必须为3。类型3仅存在值3,这意味着返回3 * 2是错误的。但3也是Int的一个实例,因此case a: Int将适用于它。只有这不能证明T =:= Int

  2. 如果不使用类型大小写和类型转换,如果没有类型类,则可以与t几乎无关。这实际上是parametricity的美丽。

  3. 如果您想拥有默认的回退实例,可以通过引入优先级来修复类型类别。

    scala> :paste
    // Entering paste mode (ctrl-D to finish)
    
    trait Manipulator[A] {
      def manip(a: A): A
    }
    
    object Manipulator extends LowerPriority {
      implicit object IntManip extends Manipulator[Int] {
        override def manip(a: Int): Int = a * 2
      }
    }
    
    trait LowerPriority {
      implicit def WhateverManip[T] = new Manipulator[T] {
        override def manip(a: T): T = a
      }
    }
    
    
    def g[T](t: T)(implicit manipulator: Manipulator[T]) = {
      manipulator.manip(t)
    }
    
    // Exiting paste mode, now interpreting.
    
    
    scala> g(2)
    res0: Int = 4
    
    scala> g(2.3)
    res1: Double = 2.3