类型别名函数类型的隐式转换类无法在Scala中编译
在scala中,以下代码可以正确编译:类型别名函数类型的隐式转换类无法在Scala中编译,scala,implicit-conversion,Scala,Implicit Conversion,在scala中,以下代码可以正确编译: class a {} class b {} object Main { implicit class Conv[f, t](val v: f ⇒ t) extends AnyVal { def conv = v } def main(args: Array[String]) { val m = (a: a) ⇒ new b m.conv } } 但由于某些原因,以下文件未能编译: class a {} cla
class a {}
class b {}
object Main {
implicit class Conv[f, t](val v: f ⇒ t) extends AnyVal {
def conv = v
}
def main(args: Array[String]) {
val m = (a: a) ⇒ new b
m.conv
}
}
但由于某些原因,以下文件未能编译:
class a {}
class b {}
object Main {
type V[f, t] = f ⇒ t
implicit class Conv[f, t](val v: V[f, t]) extends AnyVal {
def conv = v
}
def main(args: Array[String]) {
val m = (a: a) ⇒ new b
m.conv
}
}
发出以下信息:
value conv is not a member of a => b
m.conv
为什么会发生这种情况
编辑:是的,即使使用
val m: V[a,b] = new V[a,b] { def apply(a: a) = new b }
在第一个示例中,
val v:f=>t
被推断为类型签名[-a,+B]
,因为它是一个参数函数的缩写Function1
具有类型签名,Function1[-A,+B]
。因此,一种类型在a
参数中是逆变的,在B
参数中是协变的
然后lambda函数,(a:a)=>代码后面的新b
,将其类型推断为从a到b的函数。因此,类型签名是相同的,隐式解析是有效的
在第二个示例中,typeV[f,t]=f=>t
和由此创建的参数:val V:V[f,t]
,将其类型显式指定为V[f,t]
。函数f=>t
仍然是[-A,+B]
,但是您明确地将类型限制为在类型签名中保持不变,因此类型V
在两个类型参数中都是不变的
稍后,当您声明:val m=(a:a)=>new b
时,它的类型签名仍然是[-a,+b]
,如第一个示例所示。隐式解析无法工作,因为val在其第一个类型参数中是逆变的,但typeV
在其第一个类型参数中是不变的
将V的类型签名更改为V[-f,+t]
或V[-f,t]
可解决此问题,隐式解析再次起作用
这确实提出了一个问题,为什么第二类参数的协方差对于隐式解析来说不是问题,而第一类参数的逆变换是问题。我四处玩耍,做了一些研究。我发现了一些有趣的链接,这表明隐式解决方案确实存在一些限制/问题,特别是在矛盾方面
class a {}
class b {}
object Main {
type V[f, t] = f => t
implicit class Conv[f, t](val v: V[f, t]) extends AnyVal {
def conv = v
}
def main(args: Array[String]) {
val m: V[a,b] = new V[a,b] { def apply(a: a) = new b }
m.conv // does not compile
}
}
这是一个有趣的原因,我认为这是一个稍微不同的原因。类型别名在涉及差异时可以更改的方面受到限制,但允许更严格地更改差异。我不能肯定这里发生了什么,但这里有一个例子
考虑到隐式解析的复杂性,再加上类型声明差异与隐式函数1差异的其他因素,我怀疑编译器无法解析特定场景中的任何内容
改为:
implicit class Conv(val v: V[_, _]) extends AnyVal {
def conv = v
}
这意味着它在所有情况下都能工作,因为您基本上是对编译器说,对于Conv隐式类,您不关心V上类型参数的差异
e、 g:下面的方法也可以
class a {}
class b {}
object Main {
type V[f, t] = f ⇒ t
implicit class Conv(val v: V[_, _]) extends AnyVal {
def conv = v
}
def main(args: Array[String]) {
val m = (a: a) ⇒ new b
m.conv
}
}
您可以通过在类型别名中声明函数参数的方差来解决这个问题:
typev[-f,t]=f⇒ t
您没有从(a=>b)
到Conv[a,b]
的隐式转换,因此我首先认为注释类型应该有帮助val m:V[a,b]=(a:a)⇒ 新b
。但事实证明,将错误更改为值conv仍然无法编译。conv不是V[a,b]| m.conv的成员(尽管IntelliJ Idea发现了隐式转换)。谢谢,这是一个很好的答案,我一直怀疑它与方差有关。所有这些事实都没有回答我的编辑的评论,即为什么显式创建V[f,t]对象(valm:V[a,b]=new V[a,b]{def apply(a:a)=new b}
)仍然无法隐式转换为Conv
。我怀疑这是一个错误,并没有真正的答案,但以防万一,我会等待多一点关于它。还是我遗漏了什么?