协方差如何在简单函数中起作用

问题描述 投票:2回答:1

我正在尝试简单地使用Scala协方差原理。我希望下面的max和sum方法可以与ListInt或任何其他Double类型的Numeric一起使用。下面的代码返回以下错误:

type mismatch;
found: Int(2)
required: T1 
in max(List(2,3,4))
object Main extends App {

  class utils[+T1 <: Ordered[T1], +T2 <: Numeric[T1]] {

    def max(input_list: List[T1]): T1 = {

      def inside_max(i: Int, current_max: T1): T1 = {
        if (i >= input_list.size) current_max
        if (input_list(i) < current_max) {
          inside_max(i + 1, current_max: T1)
        } else {
          inside_max(i + 1, input_list(i))
        }
      }

      inside_max(0, input_list(0))
    }

    def sum(input_list: List[T2]): T2 = {

      def inside_sum(i: Int, current_sum: T2): T2 = {
        if (i >= input_list.size) current_sum
        val new_sum: T2 = implicitly[Numeric[T2]](Numeric[T2]).plus(current_sum, input_list(i))
        inside_sum(i + 1, new_sum)
      }

      inside_sum(1, input_list(0))
    }

    max(List(2,3,4))

  }

}
scala covariance
1个回答
3
投票

您正在将variancesubtypingtypeclasses混合在一起,这些是不同的概念。

在这种情况下,您实际上只想使用Numeric typeclass

object Utils {
  def max[T : Ordering](list: List[T]): Option[T] = {
    import Ordering.Implicits._

    @annotation.tailrec
    def loop(remaining: List[T], currentMax: T): T =
      remaining match {
        case Nil =>
          currentMax

        case t :: tail =>
          val newMax =
            if (t >= currentMax)
              t
            else
              currentMax

          loop(
            remaining = tail,
            newMax
          )
      }

    list match {
      case Nil => None
      case t :: tail => Some(loop(remaining = tail, currentMax = t))
    }
  }

  def sum[T : Numeric](list: List[T]): T = {
    import Numeric.Implicits._

    def loop(remaining: List[T], acc: T): T =
      remaining match {
        case Nil =>
          acc

        case t :: tail =>
          loop(
            remaining = tail,
            acc + t
          )
      }

    loop(remaining = list, acc = Numeric[T].zero)
  }
}

您可以这样使用:

Utils.sum(List(1, 2, 3))
// res: Int = 6

Utils.sum(List.empty[Int])
// res: Int = 0

Utils.max(List.empty[Int])
// res: Option[Int] = None

Utils.max(List(1, 2, 3))
// res: Option[Int] = Some(3)
© www.soinside.com 2019 - 2024. All rights reserved.