Scala: требуется ли временная переменная для обработки возвращаемого значения кортежа? - PullRequest
2 голосов
/ 20 декабря 2011

Рассмотрим следующий эскиз для использования цикла для очистки очереди в Scala:

var queue = immutable.Queue[T]( /* .. some content ..*/ )
while( !queue.isEmpty ) {
   val (record, tempQueue) = queue.dequeue
   queue = tempQueue
   doSomethingWith(record)
}

Есть ли способ избежать временной переменной tempQueue и заставить Scala назначить возвращаемое значение очереди непосредственно переменной цикла queue? Необходимость вводить дополнительный символ раздражает, плюс предположительно может быть некоторое избыточное копирование (хотя это может быть оптимизировано, не уверен).

Edit 1 : конечно, как указывает Ионут Дж. Стэн, я могу пропустить сопоставление с образцом и самостоятельно разобрать возвращенную пару, как в:

while( !queue.isEmpty ) {
   val pair = queue.dequeue
   queue = pair._2
   doSomethingWith(pair._1)
}

Итак, я должен уточнить вопрос следующим образом: есть ли способ использовать синтаксический сахар сопоставления с образцом, чтобы сделать это более элегантно? Я надеялся на что-то подобное, которое, к сожалению, не компилируется:

var queue = immutable.Queue[T]( /* .. some content ..*/ )
var record : A = _
while( !queue.isEmpty ) {
   (record, queue) = queue.dequeue
   doSomethingWith(record)
}

Ответы [ 7 ]

3 голосов
/ 20 декабря 2011

Если вы настаиваете на сохранении этой структуры (цикл while и т. Д.), Я не вижу, как вы можете сделать ее короче, за исключением, возможно,:

var queue = immutable.Queue[T]( /* some content */ )
while( !queue.isEmpty ) queue.dequeue match {
  case (record, tempQueue) =>
    queue = queue.dequeue
    doSomethingWith(record)
}

Однако, поскольку вы используете неизменяемую очередь, простейший эквивалентный код:

for(record <- queue) {
  doSomethingWith(record)
}

См. Также этот связанный вопрос , который подтверждает, что нет способа присвоить ранее существовавшему var с нотацией сопоставления с образцом.

Спецификация языка Scala , раздел 4.1, также ясна: назначения стиля сопоставления с образцом расширяются до определений val, то есть они будут связывать новый идентификатор.

2 голосов
/ 20 декабря 2011

С неизменяемыми структурами данных рекурсия - это способ реализации FP.

def foo[T](queue: immutable.Queue[T]) {
  if (!queue.isEmpty) {
    val (record, remaining) = queue.dequeue
    doSomethingWith(record)
    foo(remaining)
  }
}

foo(queue) в основном совпадает с queue foreach doSomethingWith, что предложил Брайан Смит.

2 голосов
/ 20 декабря 2011

Вы используете цикл while с неизменным Queue.Почему бы не использовать более функциональный подход (поскольку у вас все равно есть неизменный Queue)?

Вы можете определить функцию, которую вы хотите запустить для каждого элемента в Queue, а затем использовать операцию с коллекциями(карта и т. д. в зависимости от возврата вы хотите), чтобы применить его.

EG

  import scala.collection.immutable._

  val q = Queue[(Int,Int)]((1,2),(3,4),(5,6))

  def doSomethingWith(a:(Int,Int)) = {
    a swap
  }

  //returns a new Queue with each tuple's elements swapped
  q map doSomethingWith

  //returns unit (so only useful if doSomethingWith has a side effect)
  q foreach doSomethingWith   
1 голос
/ 20 декабря 2011

Вы можете использовать префиксы _, доступные до Tuple22:

scala> val a = (1,2)
a: (Int, Int) = (1,2)

scala> a._1
res0: Int = 1

scala> a._2
res1: Int = 2
0 голосов
/ 20 декабря 2011

В зависимости от условия, вы можете сначала отфильтровать список или использовать takeWhile, а затем отобразить результирующий набор. Что-то вроде

(queue takeWhile condition) foreach operation

или

(queue withFilter condition) foreach operation

Это работает, только если условие является функцией отдельного элемента. Вы также можете собрать нужную часть со сгибом (может выглядеть примерно так:)

(Nil /: queue)(<add element to accumulator if needed>) foreach operation
0 голосов
/ 20 декабря 2011

Вот небольшой взлом:

queue forall doSomethingWith

при условии, что doSomethingWith имеет тип T => Boolean

0 голосов
/ 20 декабря 2011

Вот сопоставление с образцом, но оно все еще вводит временные переменные.

while( !queue.isEmpty ) {
  queue = queue.dequeue match {
    case (t: T, q: immutable.Queue[T]) =>      
      doSomethingWith(t)
      q
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...