我有一个带有自类型注解的特征,该注解有一个类型参数。此特性来自库,不能修改。我想将此特征传递给一个函数,该函数需要类型参数的上限。例如,我有以下代码片段:
sealed trait Job[K] { self =>
type T
}
case class Encoder[T <: Product]()
def encoder(job: Job[_])(implicit ev: job.T <:< Product): Encoder[job.T] =
new Encoder[job.T]()
这将返回Type argument job.T does not conform to upper bound Product
错误和从未使用过ev
的警告。我应该如何设计encoder
函数?
2条答案
按热度按时间hc2pp10m1#
为什么不起作用?
您的问题与“广义类型约束”无关。您可以删除它,但仍然会收到相同的错误。广义类型约束用于约束该方法可以接收的参数类型。
(implicit ev: job.T <:< Product)
在作用域中提供仅当job.T <: Product
匹配的证据,仅允许调用带有Job
参数的方法,其中job.T <: Product
。这就是它的目的。您的问题是因为
Encoder
类有其类型参数T <: Product
。正如您所预期的那样,广义类型约束不会将类型job.T
本身视为Product
的子类型。证据仅适用于值参数,而不适用于类型本身,因为这就是隐式转换的工作方式。例如,假定
job.T
类型的值x
可以作为参数传递给该方法:编译第一行是因为
x
被展开为ev.apply(x)
,但第二行不能展开,无论Encoder
是否协变。第一个解决方案
您可以采取的一种解决方法是:
这样做的问题是,虽然类型参数
U
和T
都是Product
的子类型,但这个定义并没有说明它们之间的关系,编译器(甚至IntelliJ)不会推断出正确的结果类型,除非您显式指定它。例如:但是如果我们已经有了
U <: Product
,为什么还要使用job.T <:< Product
呢?相反,我们可以使用=:=
证据来确保它们的类型相等。现在,结果类型将被正确推断。
第二种变通方法
一个较短的解决方法是改用结构类型:
这不仅更干净(不需要广义类型约束),而且还避免了前面的问题。
这两个版本都可以在Scala 2.13.8上运行。
9w11ddsr2#
根据Alin的回答,您还可以使用类型别名来表示相同的内容,如下所示:
这种方法对于新手来说可能更具可读性,并且允许重复使用;然而,它本质上与Alin所做的是相同的。