Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
类型别名函数类型的隐式转换类无法在Scala中编译_Scala_Implicit Conversion - Fatal编程技术网

类型别名函数类型的隐式转换类无法在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

在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 {}
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的函数。因此,类型签名是相同的,隐式解析是有效的

在第二个示例中,type
V[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在其第一个类型参数中是逆变的,但type
V
在其第一个类型参数中是不变的

将V的类型签名更改为
V[-f,+t]
V[-f,t]
可解决此问题,隐式解析再次起作用

这确实提出了一个问题,为什么第二类参数的协方差对于隐式解析来说不是问题,而第一类参数的逆变换是问题。我四处玩耍,做了一些研究。我发现了一些有趣的链接,这表明隐式解决方案确实存在一些限制/问题,特别是在矛盾方面

我不得不向了解Scala编译器的内部结构和解析机制的人请教更多细节,但这似乎与逆变情况下隐式解析的一些限制相冲突

关于你的第三个例子,我想你的意思是:

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
。我怀疑这是一个错误,并没有真正的答案,但以防万一,我会等待多一点关于它。还是我遗漏了什么?