I'm coding against an API that gives me access to remote file system. The API returns a list of files and directories as list of node objects (parent to file and directory).
I want to work only on a directories, ignoring files. I've tried to use type pattern matching in for
loop but it does not work:
for {
dir: CSDir <- workarea.getChildren() // <-- I'm getting an error here complaining about type conversion
} {
println(dir)
}
Here is a similar example using scala basic objects to run it without dependencies:
val listOfBaseObjects:List[Any] = List[Any]("a string", 1:Integer);
for (x: String <- listOfObjects) {
println(x)
}
I end up using a regular pattern matching in side of for loop and that works fine:
// This works fien
for (child <- workarea.getChildren()) {
child match {
case dir: CSDir => println(dir)
case _ => println("do not nothing")
}
}
Can you tell me why the first /second example does not work in scala 1.9?
In the "Programming in Scala" the for
loop is advertised to use the same pattern matching as the match
so it should work.
If the for and match are different it would be great if you could point me to some articles with more details. What about pattern matching in assignment?
I can't accept an answer that states that it is impossible to skip elements in for loop as this contradicts with the "Prog. in scala". Here is a fragment from section 23.1:
pat <- expr
... The patternpat
gets matched one-by-one against all elements of that list. ... if the match fails, no MatchError is thrown. Instead, the element is simply discarded from the iteration
and indeed the following example works just fine:
scala> val list = List( (1,2), 1, 3, (3,4))
scala> for ((x,y) <- list) { println (x +","+ y) }
1,2
3,4
Why then type matching does not work?
Pattern matching is a way of checking the given sequence of tokens for the presence of the specific pattern. It is the most widely used feature in Scala. It is a technique for checking a value against a pattern. It is similar to the switch statement of Java and C.
Pattern matching is a mechanism for checking a value against a pattern. A successful match can also deconstruct a value into its constituent parts. It is a more powerful version of the switch statement in Java and it can likewise be used in place of a series of if/else statements.
Using if expressions in case statements First, another example of how to match ranges of numbers: i match { case a if 0 to 9 contains a => println("0-9 range: " + a) case b if 10 to 19 contains b => println("10-19 range: " + b) case c if 20 to 29 contains c => println("20-29 range: " + c) case _ => println("Hmmm...") }
Case classes are Scala's way to allow pattern matching on objects without requiring a large amount of boilerplate. In the common case, all you need to do is add a single case keyword to each class that you want to be pattern matchable.
This is the long-standing issue 900 and has been discussed many times before. The common workaround is to use something like:
for (y@(_y:String) <- listOfBaseObjects) {
println(y)
}
A nicer version is provided by Jason Zaugg in the comments to the above-mentioned ticket:
object Typed { def unapply[A](a: A) = Some(a) }
for (Typed(y : String) <- listOfBaseObjects) {
println(y)
}
What you want to do is essentially: iterate over all elements of workarea.getChildren()
that are of type CSDir
(in other words: matching some criteria). Ordinary loop/for comprehension iterates over all elements. You cannot say: iterate over all elements having this type and skip others. You must be more explicit.
What do you think about:
workarea.getChildren() collect {case dir: CSDir => dir} foreach println
It does exactly what you want: collect all elements of workarea.getChildren()
and for each of them call println
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With