2016-02-21 7 views
1

Я хочу использовать класс case класса Seq [Byte] как определенный список, но произошла ошибка компилятора.Как использовать класс case определить экстрактор?

Прецедент класс с ошибкой компилятора

case class :: (head: Byte, tail: Seq[Byte])   
def doMatchWithCaseClass(queue: Seq[Byte]) = {  
    queue match { 
    case h :: t => println("Good!") //can't compile 
    case _ => println("God!>_<") 
    } 
} 
doMatchWithCaseClass(Seq(1,2,3)) 

Compiler ошибка:

Error:(93, 14) constructor cannot be instantiated to expected type; 
found : :: 
required: Seq[Byte] 
     case h :: t => println("Good!") //can't compile 
      ^

UPDATE с @ Isaias-б кода после

final case class :::: (override val head: Int, override val tail: Seq[Int]) extends Seq[Int] { 
    override def length: Int = tail.length + 1 
    override def iterator: Iterator[Int] = (head :: tail.toList).toIterator 
    override def apply(idx: Int) = { 
     1.toByte // just for simple 
    } 
    } 

код матча:

def doMatchWithCaseClass(queue: Seq[Int]) = { 
    queue match { 
     case h :::: t => println("case class - Good! ^_^") 
     case x => 
     println(s"case class - God >_<! $x") 
    } 
    } 

код теста:

doMatchWithCaseClass(Seq(1,2,3)) 

консоль результат:

> case class - God >_<! List(1, 2, 3) 

выше код не любая ошибка компиляции, но это не мой ожидая результата.
Надежды кто-то может указать на mistake.thanks

ответ

0

Я не 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 = ??? 
} 

Как ошибка компилятора говорит вам, что нашла экземпляр типа ::, но необходим a 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 ключевого слова, а также. Затем были даны три заданных абстрактных метода для определения, я предоставил печатные копии на консоли. С этим можно было выполнить следующее:

scala> Seq(1,2,3) match { case ::(a, as) => "list"; case _ => "empty!" } 
res5: String = empty! 

Надеется, что это исчезает при предоставлении правильных реализаций для 3-х необходимых методов. Однако компилятор не жалуется больше ...

Update 1

@badcook отметил, что ...

Your :::: case class doesn't work because subtyping is going "the wrong way" so to speak; although your :::: is a Seq, queue is not a :::: and the latter is what matters in the pattern matching.

И он прав, простираясь всегда чувствует себя странно, когда, как правило, пытаются предпочитают композицию над наследованием. Теперь here is a comparison from Martin Odersky's online book about scala, в котором указаны различия между экстракторами, реализуемыми с использованием case class, против использования отдельных методов un/apply и un/applySeq.

Even though they are very useful, case classes have one shortcoming: they expose the concrete representation of data.

Разделительная экстрактор из представления, использует представление независимости, в его условиях. Это вызывает вопрос: трудно ли это из-за технических ограничений или мягкого выбора?Большая часть времени это не жесткий выбор:

So which of the two methods should you prefer for your pattern matches? It depends. If you write code for a closed application, case classes are usually preferable because of their advantages in conciseness, speed and static checking. If you decide to change your class hierarchy later, the application needs to be refactored, but this is usually not a problem. On the other hand, if you need to expose a type to unknown clients, extractors might be preferable because they maintain representation independence.

Fortunately, you need not decide right away. You could always start with case classes and then, if the need arises, change to extractors. Because patterns over extractors and patterns over case classes look exactly the same in Scala, pattern matches in your clients will continue to work.

Однако есть часть описания теперь есть исключения из этого основного положения!

The email addresses discussed in this chapter were one such example. In that case, extractors are the only possible choice.

Update 2

Я не 100% уверен, что снова, если это имеет место для текущего сценария, а также, говоря, если вы столкнулись случай, когда вы попали в эту ограничения. @badcook, кажется, знает это, потому что еще одна вещь, он отметил, было:

Based on your comments to other replies, it seems like you already know about extractor objects and are really just looking to see if case class can save you the effort of typing out your own unapply and unapplySeq methods for a preexisting type.

The answer is unfortunately no. You've gotta use unapply and/or unapplySeq (they're not so bad :)).

позже мы выяснили это, так что я теперь думаю, чтобы понять это сам, как хорошо. Я подведу итог разговора, произнося себя. Для этого предположим, иметь следующие case class Y(x: X):

The provided def unapply(y:Y):X method from the case class Y is strongly bound to it's input and output types. The only way to put something else into it, is using inheritance. This leads to trouble then.

И в моем текущем понимании эта беда называется представление зависимости.

+0

Я узнал, что '::' должен быть продолжен с Seq и извините, код получает «бог» не «хорошо» ..., надеюсь, кто-то сюда придет. – LoranceChen

+0

Удивительно!Спасибо, вы организуете такой ресурс. Как вы говорите, я должен использовать экстрактор для соответствия 'Seq' type.at last, What's« But, why »означает? – LoranceChen

+0

Я добавил новую информацию к сообщению и удалил «почему». Я хотел знать, почему нам придется выбирать экстрактор вместо классов case. –

1

Вы можете сопоставить непосредственно на Seq с немного отличающимся экстрактором.

def doMatch(queue: Seq[Byte]) = { 
    queue match { 
    case h +: t => println(s"Head: $h and tail: $t") 
    // You could also do case Nil =>... 
    case t  => println(s"Bad: $t") 
    } 
} 

doMatch(List(1, 2, 3)) // Head: 1 and tail: List(2, 3) 
doMatch(List())  // Bad: List() 

Edit:

Кажется, вы не просто пытаетесь соответствовать на Seq с, но имеют более общий шаблон, соответствующий на уме.

на основе ваших комментариев к другим ответам, кажется, что вы уже знаете об объектах вытяжных и на самом деле просто хотите увидеть, если case class может спасти вас усилие печатали свои собственные unapply и unapplySeq метод для ранее существовавшего типа.

Ответ, к сожалению, нет. Вы должны использовать unapply и/или unapplySeq (они не так уж плохи :)).

Ваш класс :::: не работает, потому что подтипирование идет «не так», так сказать; хотя ваш :::: является Seq, queue не является ::::, и последнее имеет значение в сопоставлении с образцом.

Узор образца видит ваш первый case и пытается найти подходящий метод unapply. К сожалению, сгенерированный метод unapply:::: имеет подпись :::: => Option[(Int, Seq[Int])], а queue не является ::::, поэтому совпадение не выполняется.

С другой стороны

object JustWriteUnapplyAndLifeWillBeGood { 
    def unapply(xs: Seq[Int]): Option[(Int, Seq[Int])] = 
    if (xs.isEmpty) None else Some(xs.head, xs.tail) 
} 

работает просто отлично.

Seq(1, 2, 3) match { 
    case JustWriteUnapplyAndLifeWillBeGood(head, tail) => 
    println(s"head: $head, tail: $tail") 
} // head: 1, tail: List(2, 3) 

// Look Ma, no prefix! 
Seq(1, 2, 3) match { 
    case head JustWriteUnapplyAndLifeWillBeGood tail => 
    println(s"head: $head, tail: $tail") 
} // head: 1, tail: List(2, 3) 

или override сгенерированный unapply метод :::: с правильной подписью.

+0

Можете ли вы дать объяснение, почему в этом случае необходимо использовать 'apply' и' unapply'? Каковы точные ограничения? См. Также мой ответ на некоторые заслуживающие доверия ресурсы. –

+0

Класс case 'Y' является по существу синтаксическим сахаром для кучи предопределенных методов, у всех аргументов и/или выходов типа' Y'. Для любых методов, которые принимают в качестве аргумента 'Y' (например,' unapply'), это означает, что для того, чтобы метод мог быть вызван в типе 'X',' X' должен быть подтипом 'Y' (т.е. контрвариантность). Если 'X' уже существует и не расширяет' 'Y', Scala не имеет возможности задним числом делать это без изменения определения' X'. В этом случае у пользователя нет возможности модифицировать 'Seq', поэтому класс case' Y' не может иметь правильный метод «unapply». – badcook

+0

Имеет смысл, как-то. Предоставленный метод 'def unapply (y: Y): X' из класса« case »Y строго связан с его типами ввода и вывода. Единственный способ вложить в него что-то еще, использует наследование. Это приводит к неприятностям. –

 Смежные вопросы

  • Нет связанных вопросов^_^