Scala: Несоответствие типов, возвращает BlockList [Any] вместо BlockList [R]

Чтобы получить больше опыта работы со Scala и в качестве эксперимента, я реализую класс, который имеет List-подобный API, но реализован как список IndexedSeq с индексом для первого элемента; tail просто возвращает копию с увеличенным индексом, а добавление Arrays равно O (1), а добавление Arrays равно O (m), m = длина списка ‹= количество элементов.

У меня проблемы с типами, возвращаемыми моей функцией. Практически каждый метод имеет параметры типа [R >: T : ClassManifest, A <: R : ClassManifest], где T является параметром типа BlockList. Иногда эти методы просто возвращают другие, но в этих ситуациях я получаю сообщение об ошибке от Eclipse, в котором говорится, что он искал тип BlockList[R], но нашел тип BlockList[Any]. Разве R не должен быть самым низким общим супертипом как для T, так и для A? В этом случае второй вызов метода также должен вернуть BlockList[R], верно? Что я не получаю? Я ClassManifest много размышляю, чтобы преодолеть проблемы стирания шрифтов, но я не знаю, остается ли это проблемой.

Ошибки взяты из определений |: и :|.

import collection.immutable.List
import reflect.ClassManifest
import annotation.tailrec

sealed abstract
class BlockList [+T] extends Seq[T] with Product {
...
}

object EmptyBlock extends BlockList[Nothing] {
...
}

class Build [T: ClassManifest](
private val block: IndexedSeq[T],
private val next: BlockList[T] = EmptyBlock,
private val index: Int = 0
) extends BlockList[T] {
require(!block.isEmpty && index >= 0 && index < block.length)

override def |: [R >: T : ClassManifest, A <: R] (x: A): BlockList[R] =
    Array[R](x) |: this //Return type error here

override def |: [R >: T : ClassManifest, A <: R : ClassManifest]
(blk: IndexedSeq[A]): BlockList[R] =
    if (blk isEmpty) this
    else new Build[R](blk, this)

override def :| [R >: T : ClassManifest, A <: R] (x: A): BlockList[R] =
    this :| Array[R](x) //Return type error here

override def :| [R >: T : ClassManifest, A <: R : ClassManifest]
(blk: IndexedSeq[A]): BlockList[R] = 
    if (blk isEmpty) this
    else new Build[R](block, next :| blk, index) //Type error here

}

person Eric    schedule 30.09.2013    source источник
comment
Я бы предложил упростить это до минимально возможного примера, который вызывает ошибку.   -  person Brian    schedule 30.09.2013
comment
Спасибо, Брайан. Я последовал твоему совету.   -  person Eric    schedule 30.09.2013


Ответы (1)


Разве R не должен быть самым низким общим супертипом как для T, так и для A?

Нет, потому что R - это верхняя граница. R может быть любым суперклассом T, и единственный класс, который удовлетворяет этой границе, - это Any.

Представьте, например, что R был AnyRef - тогда вы могли бы вызвать на нем такие методы, как eq, которые сломались бы, если было передано Int.

Итак, хотя R может быть чем-то ниже, чем Any (и, вероятно, будет большую часть времени), в то время, когда вы это объявляете, нельзя предполагать, что оно будет чем-то ниже, чем Any.

Однако я думаю, что вышесказанное не имеет никакого отношения к вашей проблеме. Ошибки, о которых вы сообщаете, появляются в этих строках, верно?

Array[R](x) |: this
this :| Array[R](x)

В другом тоже есть :|. Вы не показываете никакого неявного преобразования из Array в Build, и ни один из методов :| не принимает Array в качестве параметра (массивы не IndexedSeq).

Итак, когда вы пишете

this :| Array[R](x)

Это вызовет def |: [R1 >: T : ClassManifest, A <: R1] (x: A): BlockList[R1] (я изменил R на R1, чтобы путать с R в параметре), где тип A - Array[R], а единственный супертип T и Array[R] - Any, поэтому R1 должно быть Any, но что Any отличается от R.

Возможно, если бы вы назвали его this.:|[R, Array[R]](Array[R](x)), it would move things a little further. With the missing definitions that allowArray` переданным, я не могу предсказать ничего другого.

person Daniel C. Sobral    schedule 30.09.2013
comment
У меня создалось впечатление, что Array get автоматически переносится в WrappedArray, который сам по себе является IndexedSeq. Конструктор пока принимает Array аргумента в коде, поэтому мне кажется, что он иногда автоматически переносится. (Первоначально block был Array[T], но инвариантность Array вызвала слишком много проблем.) Я изменил эти Array[R](x) вызовы на (Array[R](x) toIndexedSeq), что, казалось, решило проблему. Теперь я не понимаю, при каких условиях Arrays неявно конвертируются в WrappedArrays. - person Eric; 30.09.2013