collect
(определено в TraversableLike и доступно во всех подклассах) работает с коллекцией и PartialFunction
.Также так получилось, что набор предложений case, определенных внутри фигурных скобок, является частичной функцией (см. Раздел 8.5 Спецификации языка Scala [warning - PDF] )
Как и в обработке исключений:
try {
... do something risky ...
} catch {
//The contents of this catch block are a partial function
case e: IOException => ...
case e: OtherException => ...
}
Это удобный способ определить функцию, которая будет принимать только некоторые значения данного типа.
Рассмотрите возможность использования ее в списке смешанных значений:
val mixedList = List("a", 1, 2, "b", 19, 42.0) //this is a List[Any]
val results = mixedList collect {
case s: String => "String:" + s
case i: Int => "Int:" + i.toString
}
Аргументом к методу collect
является PartialFunction[Any,String]
.PartialFunction
потому что он не определен для всех возможных вводов типа Any
(это тип List
) и String
, потому что это то, что возвращают все пункты.
Если вы пытались использоватьmap
вместо collect
, двойное значение в конце mixedList
приведет к MatchError
.Использование collect
просто отбрасывает это, а также любое другое значение, для которого PartialFunction не определена.
Одним из возможных применений будет применение другой логики к элементам списка:
var strings = List.empty[String]
var ints = List.empty[Int]
mixedList collect {
case s: String => strings :+= s
case i: Int => ints :+= i
}
Хотя это всего лишь пример, использование изменяемых переменных, подобных этой, многие считают военным преступлением - поэтому, пожалуйста, не делайте этого!
A намного лучшее решение - этоиспользуйте команду дважды:
val strings = mixedList collect { case s: String => s }
val ints = mixedList collect { case i: Int => i }
Или, если вы точно знаете, что список содержит только два типа значений, вы можете использовать partition
, который разбивает коллекции на значения в зависимости от того, соответствуют ли они некоторымПредикат:
//if the list only contains Strings and Ints:
val (strings, ints) = mixedList partition { case s: String => true; case _ => false }
Подвох здесь в том, что оба типа strings
и ints
относятся к типу List[Any]
, хотя вы можете легко заставить их вернуться к чему-то более безопасному (возможно, с помощью collect
)...)
Если у вас уже есть типобезопасная коллекция и вы хотите разделить некоторые другие свойства элементов, то вам будет немного проще:
val intList = List(2,7,9,1,6,5,8,2,4,6,2,9,8)
val (big,small) = intList partition (_ > 5)
//big and small are both now List[Int]s
Надеюсь, чтоподводит итог как тЗдесь вам могут помочь два метода!