2014-01-02 3 views
4

Я пытаюсь воспроизвести пример сильного образца, который Joshua Suereth представил в своем интервью Devoxx 2013 под названием «Как владеть Скалой в окопах». К сожалению, я не могу достичь того, что он описал, и я не могу понять, что не так. Может ли кто-нибудь дать мне подсказку о том, что мне не хватает? (My Scala версия 2.10.3)Почему этот шаблон не работает в Scala?

Пожалуйста, смотрите самодостаточный код ниже:

case class Person(name: String, residence: Seq[Residence]) 
case class Residence(city: String, country: String) 

object LivesIn { 
    def unapply(p: Person): Option[Seq[String]] = 
    Some(
     for(r <- p.residence) 
     yield r.city 
    ) 
} 

class StringSeqContains(value: String) { 
    def unapply(in: Seq[String]): Boolean = 
    in contains value 
} 

object PatternPower extends App { 

    val people = 
    Seq(Person("Emre", Seq(Residence("Antwerp", "BE"))), 
     Person("Ergin", Seq(Residence("Istanbul", "TR")))) 

    val Istanbul = new StringSeqContains("Istanbul") 

    // #1 does not work as expected, WHY? 
    println(
    people collect { 
     case person @ LivesIn(Istanbul) => person 
    } 
) 

    // #2 works as expected 
    println(
    people collect { 
     case person @ LivesIn(cities) if cities.contains("Istanbul") => person 
    } 
) 

    // #3 works as expected 
    println(
    people collect { 
     case person @ Person(_, res) if res.contains(Residence("Istanbul", "TR")) => person 
    } 
) 

} 

Когда я скомпилировать и запустить его я получаю:

List() 
List(Person(Ergin,List(Residence(Istanbul,TR)))) 
List(Person(Ergin,List(Residence(Istanbul,TR)))) 

Как обозначен в исходном коде , Я не понимаю, почему первый шаблон не дает того же результата, что и остальные два шаблона. Любые идеи почему?

ответ

1

После некоторого мышления и Googling, я понял, что нужно добавить () к внутреннему экстрактор (благодаря The Neophyte's Guide to Scala Part 1: Extractors).

Другими словами, следующие работы, как и ожидалось:

people collect { 
    case person @ LivesIn(Istanbul()) => person 
} 

тогда следующий код молча, без каких-либо жалоб, возвращается List():

people collect { 
    case person @ LivesIn(Istanbul) => person 
} 

Если я не ошибаюсь по-другому (например, есть способ заставить его работать без скобок), я думаю, что технические докладчики должны быть более осторожны с фрагментами кода/фрагментами псевдокода (так что некоторые из любопытных зрителей не потеряют бессонные часы ;-)

+0

, вы можете заполнить отчет об ошибке. –

+0

не уверен, если это ошибка, позвольте мне проверить с людьми на [scala-user] (https://groups.google.com/forum/#!forum/scala-user). –

+0

Это не ошибка. Без круглых скобок критерием соответствия является равенство со стабильным значением, которое является референтом указанного имени. –

6

В вашем экстракторе LivesIn требуется аргумент Seq.

Следующая вариация делает то, что вы ожидаете:

println(
    people collect { 
    case person @ LivesIn(List("Istanbul")) => person 
    } 
) 
+0

Ваш пример работает, но это не решает тайны для меня, потому что я пытаюсь понять, почему '' 'LivesIn (Istanbul)' '' не работает, где '' 'Istanbul''' определяется как' «val Istanbul = новый StringSeqContains (« Стамбул »)' ''. –

+0

Ограниченное целевое ограничение шаблона несовместимо с экстрактором. –

+0

По-прежнему пытается понять, например. следующий код '' 'List (List (« Стамбул »)) собирает {case city if Istanbul.unapply (город) => город}' '' '' '' 'Список (список (Стамбул))' ''. Я действительно не понимаю, почему значение '' '' '' '' '' '' '' '' '' '' '' StringSeqContains («Istanbul») '' 'не может использоваться как' '' LivesIn (Istanbul) '' 'для достижения ожидаемого результата. –

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