Есть ли более чистый способ сопоставления с образцом в анонимных функциях Scala? - PullRequest
35 голосов
/ 23 июня 2011

Я пишу код, подобный следующему:

val b = a map (entry =>
    entry match {
        case ((x,y), u) => ((y,x), u)
    }
)

Я хотел бы написать это по-другому, если бы только это работало:

val c = a map (((x,y) -> u) =>
    (y,x) -> u
)

Есть ли способ, которым я могу получитьчто-то близкое к этому?

Ответы [ 4 ]

54 голосов
/ 23 июня 2011

Верьте или нет, это работает:

val b = List(1, 2)
b map({case 1 => "one"
       case 2 => "two"})

Вы можете пропустить p => p match в простых случаях.Так что это должно работать:

val c = a map {case ((x,y) -> u) =>
    (y,x) -> u
}
22 голосов
/ 24 июня 2011

В вашем примере вы можете использовать три тонко различающиеся семантики.

  1. Карта коллекции, преобразующая каждый элемент, соответствующий шаблону. Бросьте исключение, если какой-либо элемент не совпадает. Эта семантика достигается с

    val b = a map { case ((x, y), u) => ((y, x), u) }
    
  2. Карта коллекции, преобразующая каждый элемент, соответствующий шаблону. Молча отбросить элементы, которые не соответствуют:

    val b = a collect { case ((x, y), u) => ((y, x), u) }
    
  3. Карта коллекции, безопасная деструкция и последующее преобразование каждого элемента. Это семантика, которую я ожидал бы для выражения типа

    val b = a map (((x, y), u) => ((y, x), u)))  
    

    К сожалению, в Scala нет краткого синтаксиса для достижения этой семантики. Вместо этого вы должны разрушить себя:

    val b = a map { p => ((p._1._2, p._1._1), p._2) }
    

    Может возникнуть соблазн использовать определение значения для деструктуризации:

    val b = a map { p => val ((x,y), u) = p; ((y, x), u) }
    

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

    val a: List[((Int, Int), Int)] = // ...
    // ...
    val b = a map { case ((x, y), u) => ((y, x), u) }
    

    Если определение a кажется далеким от его использования (например, в отдельном модуле компиляции), вы можете минимизировать риск, указав его тип в вызове карты:

    val b = (a: List[((Int, Int), Int)]) map { case ((x, y), u) => ((y, x), u) }
    
10 голосов
/ 23 июня 2011

В приведенном вами примере самое чистое решение:

val xs = List((1,2)->3,(4,5)->6,(7,8)->9)
xs map { case (a,b) => (a.swap, b) }
4 голосов
/ 23 июня 2011
val b = a map { case ((x,y), u) => ((y,x), u) }
...