gre*_*Tea 5 syntax scala implicit scala-3 given
目前正在学习 Scala 3 隐式,但我很难理解 \xe2\x80\x8bas和with关键字在如下定义中的作用:
given listOrdering[A](using ord: Ordering[A]) as Ordering[List[A]] with\n \xe2\x80\x8bdef compare(a: List[A], b: List[A]) = ...\nRun Code Online (Sandbox Code Playgroud)\n我尝试谷歌搜索,但没有找到任何好的解释。我已经检查了 Scala 3 参考指南,但我发现的唯一一件事as是它是一个“软修饰符”,但这并不能真正帮助我理解它的作用......我猜as在上面的代码以某种方式用于澄清这listOrdering[A]是一个Ordering[List[A]](就像正在进行某种类型的打字或类型转换?),但如果能找到它背后的真正含义那就太好了。
至于with,我只在 Scala 2 中使用它来继承多个特征(class A extends B with C with D),但在上面的代码中,它似乎以不同的方式使用......
非常感谢任何解释或为我指明查看文档的正确方向!
\n另外,如果用 Scala 2 编写上面的代码会是什么样子?也许这可以帮助我弄清楚发生了什么事......
\nAnd*_*kin 11
-关键字as似乎是早期 Dotty 版本中的一些工件;Scala 3 中未使用它。当前有效的语法是:
given listOrdering[A](using ord: Ordering[A]): Ordering[List[A]] with\n \xe2\x80\x8b def compare(a: List[A], b: List[A]) = ???\nRun Code Online (Sandbox Code Playgroud)\nScala书中对于在声明中使用with关键字给出了以下理由given:
\n\n由于在声明给定的别名时,通常会在等号右侧定义特征或类的匿名实例,因此 Scala 提供了一种速记语法,可以将等号和给出的别名的“new ClassName”部分替换为关键字
\nwith.
IE
\ngiven foobar[X, Y, Z]: ClassName[X, Y, Z] = new ClassName[X, Y, Z]:\n def doSomething(x: X, y: Y): Z = ???\nRun Code Online (Sandbox Code Playgroud)\n变成
\ngiven foobar[X, Y, Z]: ClassName[X, Y, Z] with\n def doSomething(x: X, y: Y): Z = ???\nRun Code Online (Sandbox Code Playgroud)\n关键字的选择with似乎并不特别重要:它只是一些已经保留的关键字,并且在这种情况下听起来或多或少是自然的。我想它听起来应该有点类似于自然语言短语,比如
\n\n“...给定整数上的幺半群结构,并带有
\na \xe2\x80\xa2 b = a * b和e = 1...”
的这种用法with特定于given-声明,并且不能推广到任何其他上下文。语言参考显示 -with关键字作为终止符号出现在产生式规则的右侧StructuralInstance,即该句法构造不能分解为仍具有该with关键字的更小的组成部分。
我相信理解塑造语法的力量比实际语法本身重要得多,所以我将描述它是如何从普通方法定义中产生的。
\nFoo让我们首先假设我们已经识别了一些常见的模式,并将其命名为Foo。像这样的东西:
trait Foo[X]:\n def bar: X\n def foo(a: X, b: X): X\nRun Code Online (Sandbox Code Playgroud)\nFoo在我们需要的地方创建实例。现在,假设我们有一些方法f需要Foo[Int]......
def f[A](xs: List[A])(foo: Foo[A]): A = xs.foldLeft(foo.bar)(foo.foo)\nRun Code Online (Sandbox Code Playgroud)\nFoo...我们可以在每次需要时写下一个实例:
f(List(List(1, 2), List(3, 4)))(new Foo[List[Int]] {\n def foo(a: List[Int], b: List[Int]) = a ++ b\n def bar: List[Int] = Nil\n})\nRun Code Online (Sandbox Code Playgroud)\nFooFoo解决方案:在我们需要的地方准确定义实例写下方法foo并bar在每次调用时f很快就会变得非常无聊和重复,所以让我们至少将其提取到一个方法中:
def listFoo[A]: Foo[List[A]] = new Foo[List[A]] {\n def foo(a: List[A], b: List[A]): List[A] = a ++ b\n def bar: List[A] = Nil\n}\nRun Code Online (Sandbox Code Playgroud)\n现在我们不必foo每次bar需要调用时都重新定义f; 相反,我们可以简单地调用listFoo:
f(List(List(1, 2), List(3, 4)))(listFoo[Int])\nRun Code Online (Sandbox Code Playgroud)\nFoo重复地写下实现usingFoo[A]在每个基本上只有一个规范的情况下A,显式传递参数listFoo[Int]很快也会变得令人厌烦,因此,我们声明listFoo为 a given,并通过添加使foo- 参数隐式:fusing
def f[A](xs: List[A])(using foo: Foo[A]): A = xs.foldLeft(foo.bar)(foo.foo)\n\ngiven listFoo[A]: Foo[List[A]] = new Foo[List[A]] {\n def foo(a: List[A], b: List[A]): List[A] = a ++ b\n def bar: List[A] = Nil\n}\nRun Code Online (Sandbox Code Playgroud)\n现在我们不必listFoo每次调用时都调用f,因为 的实例Foo是自动生成的:
f(List(List(1, 2), List(3, 4)))\nRun Code Online (Sandbox Code Playgroud)\n看起来given listFoo[A]: Foo[List[A]] = new Foo[List[A]] {有点傻,因为我们必须指定Foo[List[A]]-part 两次。相反,我们可以使用with:
\ngiven listFoo[A]: Foo[List[A]] with\n def foo(a: List[A], b: List[A]): List[A] = a ++ b\n def bar: List[A] = Nil\nRun Code Online (Sandbox Code Playgroud)\n现在,至少类型上没有重复。
\ngiven xyz: SomeTrait = new SomeTrait { }混乱,并且包含重复的部分with-syntax,避免重复由于listFoo它是由编译器自动调用的,因此我们实际上并不需要该名称,因为我们从不使用它。编译器可以自己生成一些合成名称:
given [A]: Foo[List[A]] with\n def foo(a: List[A], b: List[A]): List[A] = a ++ b\n def bar: List[A] = Nil\nRun Code Online (Sandbox Code Playgroud)\ngiven解决方案:在不需要的地方省略它们的名称。在这个过程的最后,我们的例子变成了类似的东西
\ntrait Foo[X]:\n def foo(a: X, b: X): X\n def bar: X\n\ndef f[A](xs: List[A])(using foo: Foo[A]): A = xs.foldLeft(foo.bar)(foo.foo)\n\ngiven [A]: Foo[List[A]] with\n def foo(a: List[A], b: List[A]): List[A] = a ++ b\n def bar: List[A] = Nil\n\n\nf(List(List(1, 2), List(3, 4)))\nRun Code Online (Sandbox Code Playgroud)\nfoo/bar方法List。given显式传递 s,编译器会为我们完成此操作。given定义中没有重复的类型| 归档时间: |
|
| 查看次数: |
1401 次 |
| 最近记录: |