【问题标题】:How to use given in Dotty?如何在 Dotty 中使用给定?
【发布时间】:2020-04-14 19:58:27
【问题描述】:

我正在查看Contextual Abstractions 页面下的Dotty 文档,我看到了Given Instances

给定实例(或简单地说,“给定”)定义“规范”值 用于综合给定子句的参数的某些类型。 示例:

trait Ord[T] {
  def compare(x: T, y: T): Int
  def (x: T) < (y: T) = compare(x, y) < 0
  def (x: T) > (y: T) = compare(x, y) > 0
}

given intOrd: Ord[Int] {
  def compare(x: Int, y: Int) =
    if (x < y) -1 else if (x > y) +1 else 0
}

given listOrd[T]: (ord: Ord[T]) => Ord[List[T]] {

  def compare(xs: List[T], ys: List[T]): Int = (xs, ys) match {
    case (Nil, Nil) => 0
    case (Nil, _) => -1
    case (_, Nil) => +1
    case (x :: xs1, y :: ys1) =>
      val fst = ord.compare(x, y)
      if (fst != 0) fst else compare(xs1, ys1)
  }
}

但是来自docs 的这个示例从未解释如何使用given。我提取了测试Dotty 示例项目并尝试使用它,但我不太了解它。

它是一个新的关键字吗?我们进口它吗?还是我错过了什么。

【问题讨论】:

  • 该页面上的first link 解释
  • @JoelBerkeley 我一定是瞎子,因为我没看到:(

标签: scala sbt implicit dotty scala-3


【解决方案1】:

这是使用given 实例的示例。假设我们要比较两个整数,看看哪个比另一个大。我们可以利用上面已经定义的intOrd 写:

def whichIsBigger[T](x: T, y: T)(given ord: Ord[T]): String = {
  ord.compare(x, y) match {
    case -1 => s"$x is less than $y"
    case 0 => s"$x and $y are equal"
    case 1 => s"$x is greater than $y"
  }
}

println(whichIsBigger(2, 1))

产量:

2 is greater than 1

我们之所以能够这样做,是因为作用域中有一个命名的给定实例,否则编译器会抱怨它没有 Ord[Int]

它是一个新的关键字吗?我们进口它吗?还是我错过了什么。

这是一个新关键字,它替换了 Scala 2 中 implicit 定义的特定部分。如果这是 Scala 2,我们会这样写:

implicit val intOrd: Ord[Int] = new Ord[Int] {
  def compare(x: Int, y: Int) =
    if (x < y) -1 else if (x > y) 1 else 0
}

def whichIsBigger[T](x: T, y: T)(implicit ord: Ord[T]): String

【讨论】:

  • “我们会写”...值得一提的是implicitwhichIsBigger中的位置,尤其是given是新的?
【解决方案2】:

是的,它是一个新关键字,从页面末尾的语法中使用的'given' 可以看出(“语法”部分)。它旨在替换implicit。如果你已经熟悉implicits,我认为Relationship with Scala 2 Implicits 是不错的开始。

【讨论】:

    【解决方案3】:

    也许比较一下我们如何在 Scala 2 中使用 implicit 关键字与在 Scala 3 中使用 given 关键字来定义类型类会很有启发性:

    Scala 2

    trait Semigroup[A] {
      def combine(x: A, y: A): A
    }
    
    object Semigroup {
      def combine[A: Semigroup](x: A, y: A) = implicitly[Semigroup[A]].combine(x,y)
    
      implicit val intSemigroup: Semigroup[Int] = new Semigroup[Int] {
        def combine(x: Int, y: Int) = x + y
      }
    
      implicit val quxSemigroup: Semigroup[Qux] = new Semigroup[Qux] {
        def combine(x: Qux, y: Qux) = Qux(x.a + y.a)
      }
    }
    
    case class Qux(a: Int)
    
    Semigroup.combine(41, 1)
    Semigroup.combine(Qux(41), Qux(1))
    

    Scala 3

    trait Semigroup[A] {
      def combine(x: A, y: A): A
    }
    
    object Semigroup {
      def combine[A](x: A, y: A)(given Semigroup[A]) = summon.combine(x,y)
    
      given intSemigroup: Semigroup[Int] {
        def combine(x: Int, y: Int) = x + y
      }
    
      given quxSemigroup: Semigroup[Qux] {
        def combine(x: Qux, y: Qux) = Qux(x.a + y.a)
      }
    }
    
    case class Qux(a: Int)
    
    Semigroup.combine(41, 1))
    Semigroup.combine(Qux(41), Qux(1))
    

    【讨论】:

      猜你喜欢
      • 2020-05-08
      • 1970-01-01
      • 2018-09-09
      • 1970-01-01
      • 2021-01-03
      • 1970-01-01
      • 1970-01-01
      • 2018-12-19
      • 2020-11-01
      相关资源
      最近更新 更多