奇怪的Scala编译器错误,当删除对具有单元返回类型的函数的调用时,这怎么可能呢?

奇怪的Scala编译器错误,当删除对具有单元返回类型的函数的调用时,这怎么可能呢?,scala,dependent-type,scala-implicits,Scala,Dependent Type,Scala Implicits,这里有一个奇怪的情况: 如果我使用下面的xplicittypeclassinstance注释掉对提要的调用,那么我会得到一个编译器错误 非常令人费解有什么解释吗? 我的意思是,我注释掉一个函数调用(它不返回值),然后代码就不再编译了 这在理论上是否可能?在任何编程语言中 我的意思是我注释掉了类似于println(“hello”)的东西,然后代码就不再编译了 当然,如果我注释掉一个声明或其他东西,但是调用一个不返回任何内容的函数,这是可以理解的 object AnimalFeeder extend

这里有一个奇怪的情况:

如果我使用下面的xplicittypeclassinstance注释掉对
提要的调用,那么我会得到一个编译器错误

非常令人费解有什么解释吗?

我的意思是,我注释掉一个函数调用(它不返回值),然后代码就不再编译了

这在理论上是否可能?在任何编程语言中

我的意思是我注释掉了类似于
println(“hello”)
的东西,然后代码就不再编译了

当然,如果我注释掉一个声明或其他东西,但是调用一个不返回任何内容的函数,这是可以理解的

object AnimalFeeder extends App {

  def feed_usingExplicitTypeClassInstance[AnimalInstance]
    (animalTypeClass: AnimalTypeClass[AnimalInstance])
    (food: animalTypeClass.FoodThatAnimalLikes) =
      {
          animalTypeClass.feed(food)
      }

  def feed_usingImplicitTypeClassInstance[AnimalInstance, Food]
    (food: Food)
    (implicit animalTypeClass: AnimalTypeClass.Aux[Food,AnimalInstance]) =
      {
        animalTypeClass.feed(food)
      }


  // If I comment out this line, THEN !, I get an error !!!! How ???
  feed_usingExplicitTypeClassInstance(AnimalTypeClass.CatInstance)(new CatFood())



  feed_usingImplicitTypeClassInstance(new CatFood)

}



trait Food {
  def eat(): Unit
}



trait AnimalTypeClass[AnimalInstance] {
  type FoodThatAnimalLikes <: Food
  def feed(f: FoodThatAnimalLikes) = f.eat()
}



object AnimalTypeClass {

  type Aux[Food, Animal] = AnimalTypeClass[Animal] {
    type FoodThatAnimalLikes = Food
  }

  implicit object CatInstance extends AnimalTypeClass[Cat] {
    override type FoodThatAnimalLikes = CatFood
  }

}


trait Cat

class CatFood extends Food {
  override def eat(): Unit = println("meow")
}
编辑:

如果我插入该行:

AnimalTypeClass.CatInstance
之前:

feed_usingImplicitTypeClassInstance(new CatFood)
然后代码再次编译,即使行

feed_usingExplicitTypeClassInstance(AnimalTypeClass.CatInstance)(new CatFood())

注释掉。

使用该值后,在同一文件中有隐式值的定义。当您使用ImplicitTypeClassInstance调用
提要时,当编译器查找隐式值时,它不会初始化。通过显式引用此隐式值调用
feed\u usingExplicitTypeClassInstance
,将强制隐式初始化,编译器可以在隐式调用中使用它

可能的解决办法:

  • 将隐式值的定义移动到另一个文件
  • 如果隐式值位于同一文件中,请将其定义移到隐式使用它的位置上方

这是一个众所周知的问题,在同一文件中使用隐式元素之后,如果没有显式类型注释,则找不到隐式元素。因此,强烈建议(最终将强制执行)为所有非局部隐式提供显式类型注释。不幸的是,隐式对象在这里有点棘手,因为它们总是像没有类型注释的隐式定义一样工作,并且不可能给它们一个显式类型。。。然而,上一次检查时,对于隐式对象,这似乎在Dotty中得到了修复

除其他外,另见


当您在代码中取消对
AnimalTypeClass.CatInstance
调用的注释时,它确实起作用的原因是该引用将强制隐式对象更早地进行类型检查,因此在隐式使用之前就知道其类型。

非常感谢您的回答,我现在要睡觉了,明天当我的大脑重新开始工作的时候,试着去理解它。再次感谢你的回答,所以当你说,“它的类型在它的隐含用法之前就会被知道”你这是什么意思?谁知道?编译器?那么编译器会知道它正在寻找的“类型”存在吗?或者存在该类型的隐式对象?还是类型本身?“要进行类型检查的隐式对象”是什么意思?这是否意味着编译器将一个类型与隐式对象(一个带有名称的值)关联(推断),并且当这种情况发生时,它会将隐式对象添加到它用来解析隐式对象的字典中?为了让编译器知道某个隐式对象是否符合条件,它需要知道它的类型。当定义没有类型注释时,编译器将必须处理该定义的整个主体以推断其类型。但是编译器无法在开始第一次隐式搜索之前推断所有类型,因为隐式也会影响类型推断。显然,这可能会导致推理机出现一些循环行为。但是,当您显式引用该定义时,编译器必须更早地推断其类型,以便键入使用它的当前表达式。Hmmm,因此“编译器无法在开始第一次隐式搜索之前推断所有类型”是所有这些和“当您显式引用该定义时,编译器必须更早地推断其类型,以便在使用它的地方键入当前表达式”表示编译器“知道”“隐式的类型是什么,然后它就有资格在可以使用的地方使用。非常感谢,这是一个很好的评论,解释了这种情况。非常感谢你的回答,我也是科尔玛,我现在要睡觉了,明天当我的大脑重新开始工作时试着去理解它。你的显式函数调用导致
AnimalTypeClass
对象被实例化,从而创建
隐式CatInstance
。注释掉该代码后,
AnimalTypeClass
不再实例化,因此范围中不再有
隐式AnimalTypeClass
,因此出现错误。函数调用本身是不相关的。
feed_usingExplicitTypeClassInstance(AnimalTypeClass.CatInstance)(new CatFood())