Я не уверен на 100%, является ли это желаемым решением, но, похоже, это работает:
case class ::(override val head:Int, override val tail: Seq[Int])
extends Seq[Int] {
def iterator = ???
def apply(idx: Int): Int = ???
def length: Int = ???
}
Как сообщает вам ошибка компилятора, он нашел экземпляр типа ::
, но требовал Seq[Byte]
. Я предоставил образец с Int
, который теперь расширяет Seq[Int]
, что позволило мне сделать еще один шаг.
scala> case class ::(head:Int, tail: Seq[Int]) extends Seq[Int]
<console>:10: error: overriding method head in trait IterableLike of type => Int;
value head needs `override' modifier
case class ::(head:Int, tail: Seq[Int]) extends Seq[Int]
^
Поэтому я добавил ключевое слово override
, а после очередной ошибки — ключевое слово val
. Затем осталось определить 3 заданных абстрактных метода, я предоставил заглушки, которые печатаются на консоли. При этом удалось выполнить следующее:
scala> Seq(1,2,3) match { case ::(a, as) => "list"; case _ => "empty!" }
res5: String = empty!
Надеюсь, это исчезнет при правильной реализации трех необходимых методов. Однако компилятор больше не жалуется...
Обновление 1
@badcook отметил, что...
Ваш класс :::: case не работает, потому что подтипирование идет, так сказать, "неправильным путем"; хотя ваш :::: является Seq, очередь не является :::: и последнее имеет значение при сопоставлении с образцом.
И он прав, расширение всегда кажется странным, когда обычно пытаются отдать предпочтение композиции, а не наследованию. Теперь приведу сравнение из онлайн-книги Мартина Одерски о scala, в котором различия между экстракторами, реализованными с использованием case class
es, по сравнению с использованием отдельных методов un/apply
и un/applySeq
.
Несмотря на то, что классы case очень полезны, у них есть один недостаток: они предоставляют конкретное представление данных.
Отделение экстрактора от представления использует независимость от представления, в его терминах. Возникает вопрос: это трудный выбор из-за технических ограничений или мягкий выбор? В большинстве случаев это не сложный выбор:
Итак, какой из двух методов вы должны предпочесть для сопоставления с образцом? Это зависит. Если вы пишете код для закрытого приложения, case-классы обычно предпочтительнее из-за их преимуществ в краткости, скорости и статической проверке. Если вы решите позже изменить иерархию классов, приложение необходимо будет реорганизовать, но обычно это не проблема. С другой стороны, если вам нужно предоставить тип неизвестным клиентам, экстракторы могут быть предпочтительнее, поскольку они сохраняют независимость представления.
К счастью, вам не нужно решать сразу. Вы всегда можете начать с case-классов, а затем, если возникнет необходимость, перейти к экстракторам. Поскольку шаблоны для экстракторов и шаблоны для классов case выглядят в Scala совершенно одинаково, сопоставление шаблонов в ваших клиентах будет продолжать работать.
Тем не менее, есть часть, описывающая теперь, что есть исключения из этого правила!
Адреса электронной почты, обсуждавшиеся в этой главе, были одним из таких примеров. В этом случае экстракторы - единственный возможный выбор.
Обновление 2
Я снова не уверен на 100%, справедливо ли это и для текущего сценария, говоря, если вы столкнулись со случаем, когда вы столкнулись с этими ограничениями. @badcook, кажется, знает это, потому что он указал еще на одну вещь:
Основываясь на ваших комментариях к другим ответам, кажется, что вы уже знаете об объектах-экстракторах и на самом деле просто хотите посмотреть, может ли класс case избавить вас от необходимости вводить собственные методы unapply и unapplySeq для уже существующего типа.
К сожалению, нет. Вы должны использовать unapply и/или unapplySeq (они не так уж плохи :)).
Позже мы это прояснили, так что теперь я думаю понять это и сам. Я подытожу отрывок из беседы, процитировав себя. Для этого предположим, что у вас есть следующие case class Y(x: X)
:
Предоставленный метод def unapply(y:Y):X
из case class Y
строго привязан к своим типам ввода и вывода. Единственный способ поместить в него что-то еще — использовать наследование. Тогда это приводит к неприятностям.
И в моем нынешнем понимании эта беда называется зависимость от представления.
21.02.2016
::
должен быть расширен с помощью Seq, и извините, код получился не очень хорошим…, надеюсь, кто-нибудь придет сюда. 21.02.2016Seq
. Наконец, что, но, почему? 22.02.2016Seq
является абстрактным, который мы пробовали, а String является окончательным классом. В документе, который вы указали, например, адрес электронной почты, попробуйте извлечь строку адреса в кортеж. Таким образом, в обоих случаях мы должны использовать методunapply
object сопутствующих для извлечения данных. 22.02.2016