Невозможно разрешить свидетельство класса типа, зависящего от пути, без наличия доступного типа значения

Я застрял примерно на час, чтобы обнаружить этот факт:

class Foo {
  trait TypeClass[X]
  object TypeClass {
    implicit val gimme = new TypeClass[Int]{}
  }

  def foo[X : TypeClass](p: X): Unit = println("yeah " + p)
}

    // compiles
val foo = new Foo()
foo.foo(4)

    //does not compile
new Foo().foo(4)

    could not find implicit value for evidence parameter of type _1.TypeClass[Int]
    [error]   new Foo().foo(4)
    [error]    

Я не могу понять, почему это так. Единственное, о чем я могу думать, так это о том, что scalac не находит неявные значения внутри типа, у которого нет типа значения, доступного для любого префикса. На него нельзя ссылаться. Очевидно, Scalac должен получить доступ к этому Foo.this.foo, чтобы разрешить в нем имплициты, чего в данном случае он не может.

Я чувствую, что если вы комбинируете классы типов и типы, зависящие от пути, вы фактически обречены. В конце концов, вы будете иметь дело с такими вещами. Я сделал это, потому что в противном случае scalac не вывел бы типы в моих методах API, и пользователю пришлось бы объявлять их явно. Поэтому я выбрал такой дизайн, чтобы типы конструировались в Foo[T], а методы API использовали существующий тип, но я столкнулся с несколькими действительно уродливыми проблемами и ошибками такого рода, из-за которых мое приложение выглядело как перегруженное дерьмо...


person lisak    schedule 21.12.2014    source источник


Ответы (1)


Типы, зависящие от пути, могут быть связаны только с некоторыми стабильными неизменяемыми значениями, поэтому более очевидный пример также не сработает, поскольку неизменность не гарантируется:

scala> var foo = new Foo()
foo: Foo = Foo@4bc814ba

scala> foo.foo(4)
<console>:17: error: could not find implicit value for evidence parameter of type    _37.TypeClass[Int]
          foo.foo(4)
                 ^

scala> def foo = new Foo()
foo: Foo

scala> foo.foo(4)
<console>:17: error: could not find implicit value for evidence parameter of type _39.TypeClass[Int]
          foo.foo(4)
                 ^

_37 означает, что тип не был выведен. Итак, кажется, что scala просто выводит тип только после того, как он назначен какому-то val. На самом деле это не связано с имплицитами, это даст вам более четкое объяснение:

scala> class C {type K = Int}
defined class C

scala> var z = new C
z: C = C@4d151931

scala> def aaa(a: z.K) = a
<console>:16: error: stable identifier required, but z found.
   def aaa(a: z.K) = a
              ^

scala> def z = new C
z: C

scala> def aaa(a: z.K) = a
<console>:16: error: stable identifier required, but z found.
   def aaa(a: z.K) = a
              ^

Ваше выражение new Foo похоже на def newFoo = new Foo, поэтому там оно считается нестабильным.

person dk14    schedule 21.12.2014
comment
так что последний мой фрагмент имеет неизменяемый идентификатор, который не является стабильным, потому что он находится в области действия метода, так что это тоже не работает? ` def method() = { // это также не компилируется, если находится в области действия метода val foo = new Foo() foo.foo[Int](4) }' - person lisak; 21.12.2014
comment
на самом деле у меня работает последний фрагмент - Scala REPL 2.11.2 - person dk14; 21.12.2014
comment
Я также объявил его внутри объекта (см. обновление в моем ответе) и запустил/скомпилировал с использованием scala/scalac - и он работает - person dk14; 21.12.2014
comment
Но здесь вы объявили неявный val внутри самого класса — неявные значения так не работают (они должны быть определены внутри объекта-компаньона), см. docs.scala-lang.org/tutorials/FAQ/finding-implicits.html. Или просто import foo._ - person dk14; 21.12.2014
comment
Упс, я забыл об этом, когда играл с ним, извините... Спасибо, dk14, вы поняли. - person lisak; 21.12.2014