gpt4 book ai didi

Scala 案例类副本并不总是适用于 `_` 存在类型

转载 作者:行者123 更新时间:2023-12-03 14:06:40 25 4
gpt4 key购买 nike

我正在尝试 copy()具有类型参数的 Scala 案例类。在调用站点,该值的类型为Foo[_] .
这按预期编译:

case class Foo[A](id: String, name: String, v1: Bar[A])
case class Bar[A](v: A)

val foo: Foo[_] = Foo[Int]("foo1", "Foo 1", Bar[Int](1))

foo.copy(id = "foo1.1")
但是如果我添加另一个 Bar[A] 类型的成员,它不再编译:
case class Foo[A](id: String, name: String, v1: Bar[A], v2: Bar[A])
case class Bar[A](v: A)

val foo: Foo[_] = Foo[Int]("foo1", "Foo 1", Bar[Int](1), Bar[Int](2))

foo.copy(id = "foo1.1") // compile error, see below
type mismatch;
found : Playground.Bar[_$1]
required: Playground.Bar[Any]
Note: _$1 <: Any, but class Bar is invariant in type A.
You may wish to define A as +A instead. (SLS 4.5)
Error occurred in an application involving default arguments
Scastie
到目前为止,我发现了两种解决方法:
  • 制作 Bar A 中的协变,那么问题就隐藏起来了,因为现在 Bar[_$1] <: Bar[Any]
  • 定义一个 copyId(newId: String) = copy(id = newId)方法在 Foo并调用它,那么我们就不会调用 copyFoo[_] 类型的值上.

  • 但是,对于我的用例, Bar 中的任何一个都不是真正可行的。应该是不变的,我有太多不同 copy调用 Foo[_]要制作的实例 copyThisAndThat他们所有的方法。
    我想我真正的问题是,为什么 Scala 会这样?似乎是一个错误 tbh。

    最佳答案

    编译器处理命名参数和默认参数后,调用变为

    foo.copy("foo1.1", foo.name, foo.v1)
    foo.copy("foo1.1", foo.name, foo.v1, foo.v2)
    分别。或者,如果用类型替换参数,
    foo.copy[?](String, String, Bar[_])
    foo.copy[?](String, String, Bar[_], Bar[_])
    ?copy 的类型参数必须推断。在第一种情况下,编译器基本上说“ ?Bar[_] 的类型参数,即使我不知道那是什么”。
    第二种情况下两个 Bar[_]的类型参数肯定是相同的,但是在编译器推断时该信息丢失了 ? ;他们只是 Bar[_] ,而不是像 Bar[foo's unknown type parameter] .所以例如“ ? 是第一个 Bar[_] 的类型参数,即使我不知道那是什么”也不起作用,因为据编译器所知,第二个 Bar[_]可能会有所不同。
    从它遵循语言规范的意义上说,它不是一个错误;并更改规范以允许这样做需要付出巨大的努力,并使它和编译器都变得更加复杂。对于这种相对罕见的情况,这可能不是一个好的权衡。
    另一种解决方法是使用类型变量模式来临时为 _ 命名。 :
    foo match { case foo: Foo[a] => foo.copy(id = "foo1.1") }
    编译器现在看到 foo.v1foo.v2都是 Bar[a]等等 copy 的结果是 Foo[a] .离开后 case分支变成 Foo[_] .

    关于Scala 案例类副本并不总是适用于 `_` 存在类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62873718/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com