【问题标题】:Scala List with type parameter带有类型参数的 Scala 列表
【发布时间】:2018-04-27 03:22:09
【问题描述】:

我在编写一个名为 head 的函数时遇到了问题,该函数基本上用另一个元素替换了调用它的 List 的 head 元素:

List(1,2,3,4).head(4) // List(4,2,3,4)

代码显然没用,我只是想玩 Scala。这是代码:

sealed trait List[+A]{
  def tail():List[A]
  def head[A](x:A):List[A]
}

object Nil extends List[Nothing]{
  def tail() = throw new Exception("Nil couldn't has tail")
  def head[A](x:A): List[A] = List(x)
}

case class Cons[+A](x :A, xs: List[A]) extends List[A]{
  def tail():List[A] = xs
  def head[A](a:A): List[A] = Cons(a,xs)
}

object List{
  def apply[A](as:A*):List[A] = {
    if (as.isEmpty) Nil
    else Cons(as.head,apply(as.tail: _*))
  }
}

Cons(1,Cons(2,Nil)) == List(1,2)
Cons(1,Cons(2,Cons(3,Cons(4,Nil)))).tail()
List(1,2,3,4,5,6,7).tail()
List(1,2,3,4).head(4)

它没有编译,我有这个错误:

Error:(11, 39) type mismatch;
found   : A$A318.this.List[A(in class Cons)]
required: A$A318.this.List[A(in method head)]
 def head[A](a:A): List[A] = Cons(a,xs)

请你解释一下为什么?

问候。

【问题讨论】:

    标签: scala


    【解决方案1】:

    您的问题是您的head 方法采用另一种类型A,因此在该范围内,编译器将那些As 视为不同,即特征中定义的A 被@ 遮蔽987654325@head[A]

    另外,您的head 方法将A 类型的协变元素置于逆变位置,因此您不能这样定义head

    您可以将head 定义为:

    def head[B >: A](x: B): List[B]
    

    因此,你得到:

    object S {
        sealed trait List[+A] {
            def tail(): List[A]
            def head[B >: A](x: B): List[B]
        }
    
        case object Nil extends List[Nothing] {
            def tail() = throw new Exception("Nil doesn't have a tail")
            def head[B >: Nothing](x: B): List[B] = Cons(x, Nil)
        }
    
        case class Cons[+A](x: A, xs: List[A]) extends List[A] {
          def tail(): List[A] = xs
          def head[B >: A](a: B): List[B] = Cons(a, xs)
        }
    
        object List {
          def apply[A](as: A*): List[A] = {
            if (as.isEmpty) Nil
            else Cons(as.head, apply(as.tail: _*))
          }
        }
    }
    

    在 REPL 上测试:

    scala> :load test.scala
    Loading test.scala...
    defined object S
    
    scala> import S._
    import S._
    
    scala> Nil.head(1)
    res0: S.List[Int] = Cons(1,Nil)
    
    scala> Cons(1, Nil).head(4)
    res1: S.List[Int] = Cons(4,Nil)
    

    【讨论】:

    • 所以基本上使用我的类型参数 A inside head 方法,我就像在定义我的类时使用的原始类型参数 A 一样,对吧?
    • 没错。 head 方法中的 A 会影响 trait 中的 A
    【解决方案2】:

    您的方法 head 不需要类型参数,因为您已经在类定义中定义了一个类型参数,而这正是您希望 head 接收的类型(如果您希望 head 创建与原始类型相同的列表)。

    您得到的错误是因为 A 在方法头的上下文中是两种不同的类型(一种来自方法,另一种来自类)。

    head 的定义应该是:

    def head(x:A):List[A]
    

    【讨论】:

    • 不,这不正确。 A 是协变的,您将其置于逆变位置。
    猜你喜欢
    • 2014-10-06
    • 2023-03-15
    • 2015-10-13
    • 1970-01-01
    • 1970-01-01
    • 2017-06-29
    • 2013-06-14
    • 2019-05-06
    • 2017-10-31
    相关资源
    最近更新 更多