今天我清除了 .ivy 缓存并清理了我的项目输出目标。从那时起,当我使用 SBT 运行测试或在 Scala IDE 中进行编辑时,我遇到了非常奇怪的行为。
鉴于以下情况:
package com.abc.rest
import com.abc.utility.IdTLabel
我会收到以下错误:
object utility is not a member of package com.abc.rest.com.abc
请注意,
com.abc
重复了两次,因此编译器在执行导入时似乎使用了当前包的上下文(也许它应该这样做,但我以前从未注意到)。
此外,如果我尝试从
com.abc
内的任何位置访问包 com.abc.rest
中的类(即使使用完整路径),编译器也会抱怨找不到该类型。
看来,错误仅在我尝试包含父包中的文件时才会发生。我确实觉得奇怪的是我的代码曾经可以工作。它是在我清理了我的项目和 ivy 缓存后才开始发生的,所以也许更高版本的编译器比以前的版本更严格。
我希望能得到一些关于我可能做错了什么的想法,或者我如何解决这个问题。
更新:
通过首先导入父类,然后定义当前包,问题就消失了:
import com.abc.utility.IdTLabel
import com.abs._
package com.abc.rest {
// Define classes belonging to com.abc.rest here
}
所以这可行,但我仍然很想知道为什么相反的方式有效,然后停止工作,以及我到底如何解决它。我仔细一看,在父包内的任何地方都找不到名为 com 的包、对象或特征。
与工作表相关的更新:
属于同一包的 Scala 工作表共享相同的范围,这听起来很明显,但事实并非如此。工作表不是沙盒的 - 它们可以看到项目,项目也可以看到它们。因此,您在工作表文件中创建的所有“测试”对象、特征和类在项目的其余部分中也变得可见。
我有太多的工作表,我什至没有尝试看看问题出在哪里。我只是将它们全部移动到自己的包中,就像魔术一样,问题就消失了。
所以,今天的经验教训:如果您在工作表内创建内容,则从工作表外部可以看到它。
无论如何,这些新发现的知识将会派上用场,这意味着可以在工作表中构建、监控和调整任何“有趣”的内容,而项目的其余部分实际上可以使用它。其实很酷。
思考
sbt clean
和清理的常春藤缓存如何设法突出之前隐藏的问题仍然很有趣,但是,嘿,那是另一个故事了......
(应 JacobusR 的要求,我根据之前的评论做出正确的回答)。
如果您在包中定义了某些类/特征/对象,则可能会发生这种情况
com.abc.rest.com
。一旦包 com.abc.rest.com
存在,并且考虑到您位于包 com.abc.rest
中,com
将指定 com.abc.rest.com
而不是 _root_.com
。最快(但非决定性)的检查方法是在“com/abc/rest/com”子文件夹中查找任何 .class 文件,甚至无需扫描源文件。
特别是,如果您的任何文件具有重复的包定义(如包
com.abc.rest; package com.abc.rest; ...
中),您将会遇到此行为。如果在出现错误的同一文件中的某处存在此重复的包子句,您甚至不会看到 .class 文件有任何可疑之处,因为编译文件失败将阻止为任何类生成 .class 文件文件内的定义。
最后一点有用的信息是,正如您发现的那样,scala 工作表没有沙箱,并且您在工作表中定义的内容会影响项目的代码(而不仅仅是项目的代码影响工作表)。因此,工作表中的重复包子句很可能会导致您遇到的错误。
__root__
开始,查看指定完整路径是否可以解决问题。前任。
import __root__.com.foo.bar._