首页 文章

Scala类型边界

提问于
浏览
2

下面的代码有什么问题?我在指定的行上从编译器收到以下抱怨:类型参数[Asset]不符合trait Worker的类型参数bounds [T <:br.Doable]

这是怎么回事? Worker期望子类型为Doable,资产扩展为Doable .

trait Doable

trait Worker[T<:Doable] {
  def hey():String
}

case class Asset() extends Doable

case class Hey[Asset] extends Worker[Asset] { // << error here
  def hey() = "You!"
}

3 回答

  • 2

    当您声明 case class Hey[Asset] 时,绑定一个新的类型变量 Asset ,您没有引用 case class Asset() extends Doable (您正在隐藏 Asset 类型变量) . 您的代码相当于:

    case class Hey[A] extends Worker[A] {
        ...
      }
    

    这显然是行不通的 .

  • 6

    问题是你通过使用相同的值 Asset 来引用案例类和类型参数而使自己感到困惑 .

    你可能打算做这样的事情:

    case class Hey[T](str: String) extends Worker[Asset] { 
      def hey() = "You!"
    }
    

    虽然它不是重点,但请注意我向 Hey 添加了一个参数,因为不推荐使用没有参数的case类 .

  • 0

    这已被问过很多次了,我认为如果你看到类型参数和构造函数参数之间的类比,将它们视为不同类型的构造函数参数:类型级别和值级别,那么混淆很容易消失 .

    免责声明当然,这只是一个类比,它将在很多不同的层面上破解,并且有许多角落案例与Scala一样;但我的观点是它可能有用

    在类型级别,您可以将 <: 视为值等级 :

    class TypeParamsVsVals {
    
      type X
      type X1 <: X
    
      class Buh[T <: X]
      class Oh[T1 <: X1] extends Buh[T1]
      // wait for Scala 3
      // class Oh[T1 <: X1] extends Buh[T = T1]
    
      type x
      type x1 <: x
    
      class buh(val t: x)
      class oh(val t1: x1) extends buh(t = t1)
    }
    

    我认为混淆的主要原因是,在类型层面上, <: 的双方之间没有任何区别,更糟糕的是你可以在没有任何(没有双关语意图)限制的情况下编写 T ,而你却不能这样做在 Value 水平:

    class NoBounds[T]
    // same as 
    class AltNoBounds[T <: Any]
    
    // you cannot write
    // class noBounds(val t)
    class noBounds(val t: Any)
    

相关问题