scala - Scala 隐式泛型类型自动推断
问题描述
我想构建一个转换方法以通过构建器输出特定类型,但根据情况,最后一个是否采用隐式位置将修改泛型类型自动推断。我很乐意了解更多有关的好奇行为。
trait Wrap[A]
trait Toto[A, W <: Wrap[A]] {
def fail[A2, W2 <: Wrap[A2], T2 <: Toto[A2, W2]](f: W => W2)(implicit builder: Builder[A2, W2, T2]): T2
def works[A2, W2 <: Wrap[A2], T2 <: Toto[A2, W2]](f: W => W2, builder: Builder[A2, W2, T2]): T2
}
trait Builder[A, W <: Wrap[A], T <: Toto[A, W]]
type A1
type W1 <: Wrap[A1]
type A2
type W2 <: Wrap[A2]
type T2 <: Toto[A2, W2]
val t1: Toto[A1, W1]
implicit val builder: Builder[A2, W2, T2]
val f: W1 => W2
t1.fail(f) // inferred type arguments [Nothing, W2, Nothing] do not conform to method fail's type parameter
t1.fail(f)(builder) // inferred type arguments [Nothing, W2, Nothing] do not conform to method fail's type parameter
/**
* [error] found : Test.this.W1 => Test.this.W2
* [error] required: Test.this.W1 => W2
*/
t1.works(f, builder) // compiles
解决方案
事情不是隐含的。如果你works
用两个参数列表重写
def works1[A2, W2 <: Wrap[A2], T2 <: Toto[A2, W2]](f: W => W2)(builder: Builder[A2, W2, T2]): T2
这也行不通。如果f
和builder
在同一个参数列表中,那么在
t1.works(f, builder)
A2, W2, T2
是推断出来的,但是如果f
在第一个参数列表中并且builder
在第二个参数列表中,那么在
t1.works1(f)(builder)
// ^
// here
f
仅从第一个参数列表W2
中推断正确,因此A2
推断T2
为Nothing
,然后在第二个参数列表的类型检查期间返回并修复推断为时已晚,并且失败了。
所以如果你想使用隐式builder
(然后你不能使用单个参数列表)尝试重写你的代码。尝试用隐式约束替换类型边界(这会改变类型推断的顺序),然后你必须用抽象类替换特征,以便它们可以具有隐式参数
trait Wrap[A]
abstract class Toto[A, W](implicit ev: W <:< Wrap[A]) {
def fail1[A2, W2, T2](f: W => W2)(implicit builder: Builder[A2, W2, T2], ev1: W2 <:< Wrap[A2], ev2: T2 <:< Toto[A2, W2]): T2
}
abstract class Builder[A, W, T](implicit ev: W <:< Wrap[A], ev1: T <:< Toto[A, W])
t1.fail1(f) //compiles
推荐阅读
- oracle - Oracle 12c:使用用户定义的函数结果和 In 子句
- html - Xpath 节点集嵌套顺序选择
- android - Android - 资源解析如何影响构建性能?
- react-native - 如何在本地存储中存储和读取json文件的文件内容
- flutter - CheckboxListTile 中如何激活/停用?
- javascript - 如何向客户端发送数据并将其保存为 cookie
- python - 对具有多个值的字典进行排序
- html - CSS Div 不居中
- javascript - JSON 数据仅填充 DataTable 中的第一个字母
- serverless-framework - 我怎样才能看到无服务器部署正在使用哪些对象?