I just discovered that unapply in my extractor is being called twice for some reason. Anyone know why, and how to avoid it?
val data = List("a","b","c","d","e")
object Uap {
def unapply( s:String ) = {
println("S: "+s)
Some(s+"!")
}
}
println( data.collect{ case Uap(x) => x } )
This produces output:
S: a
S: a
S: b
S: b
S: c
S: c
S: d
S: d
S: e
S: e
List(a!, b!, c!, d!, e!)
The final result is fine but in my real program the unapply is non-trivial, so I certainly don't want to call it twice!
collect takes a PartialFunction
as input. PartialFunction
defines two key members: isDefinedAt
and apply
. When collect runs your function, it runs your extractor once to determine if your function isDefinedAt
some particular input, and if it is, then it runs the extractor again as part of apply
to extract the value.
If there is a trivial way of correctly implementing isDefinedAt, you could implement this yourself by implementing your own PartialFunction explicitly, instead of using the case syntax. or you could do a filter
and then map
with a total function on the collection (which is essentially what collect is doing by calling isDefinedAt
, then apply
)
Another option would be to lift
the Partial function to a total function. PartialFunction
defines lift
which turns a PartialFunction[A,B]
into a A=>Option[B]
. You could use this lifted function (call it fun
) to do: data.map(fun).collect { case Some(x) => x }