Дженерики Scala: ковариантность/контравариантность в двухуровневой структуре данных

У меня есть алгоритм, который работает с индексированными последовательностями некоторых объектов: он получает две такие последовательности и должен вывести одну результирующую последовательность. Я хотел бы, чтобы он мог работать по крайней мере с:

  • Символы в строке
  • Строки (строки) в массиве текста

Для простоты предположим, что этот алгоритм просто строит новую последовательность объектов, получая объекты один за другим из каждой исходной последовательности. Есть некоторые особые случаи, когда мне нужно вернуть либо пустую последовательность объектов нужного типа, либо исходные объекты. Единственные две операции, которые я бы использовал для исходных последовательностей:

  • получение i-го элемента по индексу
  • получение размера последовательности

Мой текущий код выглядит так:

class GenericTest[C, T <: IndexedSeq[C]](a: T, b: T) {
  def run: T = {
    // special case #1: need to return empty sequence here
    if (a.size == 0) {
      // what I've tried:

      return new T()
      // fails: "class type required but T found"

      return Seq[C]()
      // fails: "type mismatch; found : Seq[C] required: T"

      return Array[C]()
      // fails: "not enough arguments for method apply: (implicit
      // evidence$2: scala.reflect.ClassTag[C])Array[C] in object
      // Array. Unspecified value parameter evidence$2."

      return Array.ofDim[C](0)
      // fails: "No ClassTag available for C"
      // "not enough arguments for method ofDim: (implicit
      // evidence$3: scala.reflect.ClassTag[C])Array[C].
      // Unspecified value parameter evidence$3."
    }

    // special case #2: need to return original input here
    if (a == b) {
      return a
      // it works
    }

    val result = new MutableList[C]

    for (i <- 0 until scala.math.min(a.size, b.size)) {
      result += a(i)
      result += b(i)
    }

    // what I've tried:

    return result
    // fails: "type mismatch; found : result.type (with underlying
    // type scala.collection.mutable.MutableList[C]) required: T"

    return result.toIndexedSeq
    // fails: "type mismatch; found : scala.collection.immutable.IndexedSeq[C]
    // required: T"
  }
}

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

  • Возвращает пустую последовательность объектов
  • Возвращает построенную последовательность объектов
  • Вернуть исходный ввод

Я предполагаю, что этот вопрос требует аннотаций ковариации/контравариантности для типа, мне кажется, что мне не хватает ковариантности...


person GreyCat    schedule 12.10.2013    source источник


Ответы (1)


Поскольку списки в scala являются ковариантными, вы можете добавить в список любой объект, если он является подтипом типа списка.

   class GenericTest[C](a: IndexedSeq[C], b: IndexedSeq[C]) {
      def run: IndexedSeq[C] = {
        // special case #1: need to return empty sequence here
        if (a.size == 0) {
          return IndexedSeq.empty[C]
        }

        // special case #2: need to return original input here
        if (a == b) {
          return a
        }

        val result = mutable.ArrayBuffer[C]()

        for (i <- 0 until scala.math.min(a.size, b.size)) {
          result += a(i)
          result += b(i)
        }
        result.toIndexedSeq
      }
    }
person Harshal Pandya    schedule 12.10.2013