gpt4 book ai didi

Scala:指定默认泛型类型而不是 Nothing

转载 作者:行者123 更新时间:2023-12-03 23:49:35 26 4
gpt4 key购买 nike

我有一对看起来像这样的类(class)。有一个 Generator根据一些类级别的值生成一个值,和一个 GeneratorFactory构造一个 Generator .

case class Generator[T, S](a: T, b: T, c: T) {
def generate(implicit bf: CanBuildFrom[S, T, S]): S =
bf() += (a, b, c) result
}

case class GeneratorFactory[T]() {
def build[S <% Seq[T]](seq: S) = Generator[T, S](seq(0), seq(1), seq(2))
}

你会注意到 GeneratorFactory.build接受类型为 S 的参数和 Generator.generate产生类型 S 的值,但没有类型 SGenerator 存储.

我们可以像这样使用这些类。工厂按照 Char 的顺序进行工作, 和 generate产生 String因为 build得到一个 String .
val gb = GeneratorFactory[Char]()
val g = gb.build("this string")
val o = g.generate

这很好,可以处理 String隐式类型,因为我们使用的是 GeneratorFactory .

问题

现在当我想构建一个 Generator 时问题就出现了无需经过工厂。我希望能够做到这一点:
val g2 = Generator('a', 'b', 'c')
g2.generate // error

但我收到一个错误,因为 g2有类型 Generator[Char,Nothing]和 Scala“无法基于类型为 Nothing 的集合构造具有类型为 Char 的元素的类型为 Nothing 的集合。”

我想要的是一种告诉 Scala S 的“默认值”的方法。类似于 Seq[T]而不是 Nothing .借用默认参数的语法,我们可以将其视为如下内容:
case class Generator[T, S=Seq[T]]

解决方案不足

当然,如果我们明确告诉生成器它生成的类型应该是什么,它就可以工作,但我认为默认选项会更好(我的实际场景更复杂):
val g3 = Generator[Char, String]('a', 'b', 'c')
val o3 = g3.generate // works fine, o3 has type String

我想过重载 Generator.apply有一个通用类型的版本,但这会导致错误,因为显然 Scala 无法区分这两个 apply定义:
object Generator {
def apply[T](a: T, b: T, c: T) = new Generator[T, Seq[T]](a, b, c)
}

val g2 = Generator('a', 'b', 'c') // error: ambiguous reference to overloaded definition

期望输出

我想要的是一种简单地构建 Generator 的方法。不指定类型 S并将其默认为 Seq[T]这样我就可以:
val g2 = Generator('a', 'b', 'c')
val o2 = g2.generate
// o2 is of type Seq[Char]

我认为这对用户来说是最干净的界面。

有什么想法可以让我做到这一点吗?

最佳答案

您是否有理由不想使用基本特征然后缩小范围 S根据其子类的需要?以下示例符合您的要求:

import scala.collection.generic.CanBuildFrom

trait Generator[T] {
type S
def a: T; def b: T; def c: T
def generate(implicit bf: CanBuildFrom[S, T, S]): S = bf() += (a, b, c) result
}

object Generator {
def apply[T](x: T, y: T, z: T) = new Generator[T] {
type S = Seq[T]
val (a, b, c) = (x, y, z)
}
}

case class GeneratorFactory[T]() {
def build[U <% Seq[T]](seq: U) = new Generator[T] {
type S = U
val Seq(a, b, c, _*) = seq: Seq[T]
}
}

我已经做了 S一种抽象类型,以使其更不受用户影响,但您也可以将其设为类型参数。

关于Scala:指定默认泛型类型而不是 Nothing,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11811267/

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