В Scala, почему я получаю это "полиморфное выражение не может быть создано для ожидаемого типа"?
Почему в Scala 2.9.0.1?
происходит следующее:
scala> def f(xs: Seq[Either[Int,String]]) = 0
f: (xs: Seq[Either[Int,String]])Int
scala> val xs = List(Left(0), Right("a")).iterator.toArray
xs: Array[Product with Serializable with Either[Int,java.lang.String]] = Array(Left(0), Right(a))
scala> f(xs)
res39: Int = 0
scala> f(List(Left(0), Right("a")).iterator.toArray)
<console>:9: error: polymorphic expression cannot be instantiated to expected type;
found : [B >: Product with Serializable with Either[Int,java.lang.String]]Array[B]
required: Seq[Either[Int,String]]
f(List(Left(0), Right("a")).iterator.toArray)
^
Обновление: Дебильски предлагает лучший пример (не на 100% уверен, что это демонстрирует одно и то же основное явление):
Seq(0).toArray : Seq[Int] // compiles
Seq(Some(0)).toArray : Seq[Option[Int]] // doesn't
Ответы
Ответ 1
Лучшим человеком, который объяснит это, является Adriaan Moors, и он уже сделал это здесь, на Qaru - найти ответы от него, и вы его найдете.
В любом случае проблема заключается в том, что тип List(Left(0), Right("a")).iterator.toArray
не может быть выведен в пределах границ, ожидаемых f
. Он не соответствует Seq[Either[Int, String]]
без неявного преобразования, и не может быть применено неявное преобразование, потому что оно (тип) не может быть определено. Это как проблема с яйцом и курицей.
Если вы используете <%
или присваиваете его значению val, вы прерываете цикл в выводе.
Ответ 2
Это не имеет никакого отношения к Either
, а скорее к обработке Array
. Если вы преобразуете его вручную в Seq
, он работает:
scala> f(xs.toSeq)
res4: Int = 0
A Scala Array
не является Seq
(потому что это фактически массив Java). Но a WappedArray
есть. Вы также можете переопределить свою функцию f
:
scala> def f[A <% Seq[Either[Int,String]]](xs: A) = 0
f: [A](xs: A)(implicit evidence$1: (A) => Seq[Either[Int,String]])Int
scala> f(xs)
res5: Int = 0
Кстати, не нужно получать итератор перед вызовом toArray
.
Ответ 3
Я считаю, что это связано с тем, что вы не можете превратить Array в массив, но вы можете преобразовать последовательность в массив. Метод хочет, чтобы Sequence использовалась для создания массива.
Нижняя строка - проверить сигнатуры метода и не угадать, на чем они основаны на имени метода.
Важная часть:
found : [B >: Product with Serializable with Either[Int,java.lang.String]]Array[B]
required: Seq[Either[Int,String]]
f(List(Left(0), Right("a")).iterator.toArray)
В методе toArray
требуется Seq (так что List будет в порядке), и он возвращает массив. Вы передали ему массив, и он не знает, что делать. Либо сначала создайте массив в Seq, либо просто пропустите метод toArray
.
Если вы вернетесь на один шаг, становится ясно, что метод iterator
принимает ваш список и возвращает массив. Каждый вызов метода является вызовом функции.