包中的隐含解决方案



在离开Scala几年后,我一直在重新学习它。我现在正在努力理解隐式和隐式解析(这在过去一直是我的问题)。我遇到了一些事情,这表明我可能有一个比我想象的更根本的误解——尤其是在范围界定和导入方面。

考虑以下内容:

class A {
def test(using n: Int): String = n.toString
}
object A {
given n: Int = 2
}
object Main extends App {
println((new A()).test)
}

如果我试图编译这个,我会得到以下错误:

在A类中,没有为方法测试的参数n找到Int类型的隐式参数

我不明白为什么会这样。如果我将打印表达式更改为以下内容:

println((new A()).test(using A.n))

它是有效的(我花了很长时间才发现这实际上是一种允许的语法)。

显然,另一个解决方案是执行以下操作:

import A.given
println((new A()).test)

这同样有效。

根据这个答案,在一个类型的伴随对象中搜索隐含词(这里就是这样)。所以,我的问题是,我想,为什么编译器允许我直接引用A.n,但它自己却找不到那个隐式值?为什么需要进口?它看起来很像是在范围内,应该得到解决。

我的困惑部分来自文档:

import子句用于访问其他包中的成员(类、特征、函数等)。访问同一程序包的成员不需要import子句。

(来自文档)。由于CCD_ 3是"0";同一包装的一部分";为什么我需要导入它或它的任何成员?通常,当类或对象在作用域中并且可见时,什么时候需要导入成员?这是Scala3中发生了变化吗?

编辑

只是四处玩耍,我还尝试了以下方法:

class A {
def test(using n: Int): String = n.toString
}
object A {
given n: Int = 2
}
given n: Int = 5
object Main extends App {
import A.given
println((new A()).test)
}

我本以为会得到一个关于不明确的隐式解析的编译器错误,但它成功了,并打印了2。我不明白为什么会这样。如果我注释掉导入,它将打印5,这至少与我在上面看到的内容一致。

在A类中,没有为方法测试的参数n找到Int类型的隐式参数

在这种情况下,作用域中没有implicit/givenInt

PS:我想你已经意识到了,这只是一个练习,但像Int这样的东西永远不应该是implicit

我不明白为什么会这样。如果我将打印表达式更改为以下内容:
println((new A()).test(using A.n))
,则它工作于

好吧,在这种情况下,显式传递参数,就不再有隐式解析了。

你甚至可以做一些类似的事情

println((new A()).test(using 3))

还是一样,那里没有什么新奇的事情发生。

显然,另一个解决方案是执行以下操作:
import A.given

在这种情况下,您将把object A中的所有given值添加到当前作用域中。

当然,这解决了最初的问题,因为现在范围中有一个given Int,并且隐式解决方案可以按预期工作。

根据这个答案,在一个类型的伴随对象中搜索隐含词(这里就是这种情况)。

事实并非如此
此处的类型为IntInt的伴随object未定义任何given值。

所以,我想我的问题是,为什么编译器允许我直接引用A.n,但它自己却找不到那个隐式值?

它允许您引用它,因为编译器总是允许您使用相对路径或完整路径引用任何值(只要有可见性约束)。这和你编写任何代码时所做的一样,这里没有任何与隐词相关的内容。

同样,编译器找不到它,因为这样的值不在隐式范围内,所以编译器不会查找它

(来自文档)。由于对象A是"0";同一包装的一部分";为什么我需要导入它或它的任何成员?

您不需要导入它来访问其成员,就像您之前展示的那样,您可以轻松访问A.n

我本以为会得到一个关于不明确的隐式解析的编译器错误,但它成功了,并打印了2。我不明白为什么会这样。如果我评论掉它打印的导入5,这至少与我上面看到的一致。

这个实际上很棘手,但隐式解析有权重的概念。规范规定,如果在作用域中找到两个隐式值,将选择最具体的一个。只有当两者具有相同的权重时,才会出现不明确的错误。

就进口而言,它们的重量总是更大。并且进一步进口";影子以前的(这也发生在正则值btw中)


还有建议,如果你用一个真实的例子,也许会更容易理解;不是Int

相关内容

  • 没有找到相关文章

最新更新