Why does scala complain when given this pattern match on an integral value?
Goal: Write a function that generates a new String excluding a specified character (identified by the index)
Example开发者_StackOverflow:
takeAllExcept(0, "abc")
returnsbc
takeAllExcept(1, "abc")
returnsac
takeAllExcept(2, "abc")
returnsab
What I did initially:
def takeAllExcept( index: Int, s: String ): String = {
val lastIndex = s.length()-1
index match {
case 0 => return s.slice(1, s.length)
case lastIndex => return s.slice(0, s.length()-1)
case _ => { s.slice(0, index) + s.slice(index+1, s.length) }
}
}
The compiler complains that the statement block for case _
is unreachable.
How I fixed it
def takeAllExcept( index: Int, s: String ): String = {
val lastIndex = s.length()-1
if( index == 0 )
return s.slice(1, s.length)
if( index == lastIndex )
return s.slice(0, s.length()-1)
s.slice(0, index) + s.slice(index+1, s.length)
}
I want to know why my initial attempt failed with the unreachable code. It looks legit to me. Also, is there an in-built facility in scala that already does this ?
lastIndex
in the pattern is an implicit declaration of a new name that is bound to whatever value is put into the match and shadows the allready defined lastIndex
, as the other two post allready pointed out. There are two other possibilities instead of using upper case identifiers (see Peter's post):
Using backticks to let the compiler know that this shall not be a declaration of a new identifier:
case `lastIndex` => ...
Using pattern guards:
case x if x == lastIndex => ...
If you want to do a lot of index-based removing on strings then it would be faster to use a Buffer by calling toBuffer
on the string and then you can use the remove(i: Int)
method of Buffer. That is slower for only one operation because you will have to convert the Buffer back to string when your done but if you do many random access operations its a lot faster. After your done you can call mkString
on the Buffer to get your String back. For single removal I would do it like Peter suggested or here is an alternative:
def takeAllExcept(i: Int, s: String) = s.take(i) + s.drop(i+1)
Your first question:
def takeAllExcept( index: Int, s: String ): String = {
val LastIndex = s.length()-1
index match {
case 0 => return s.slice(1, s.length)
case LastIndex => return s.slice(0, s.length()-1)
case _ => { s.slice(0, index) + s.slice(index+1, s.length) }
}
}
The lastIndex
after the case
is newly bound while pattern matching and hides the definition of val lastIndex = s.length()-1
. As my example shows, you can use upper case names, then scala uses a defined val
in scope.
To answer your second question in a way I would solve it:
def takeAllExcept(i: Int, s: String): String = {
val (prefix,suffix) = s.splitAt(i)
prefix + suffix.tail
}
val lastIndex = s.length()-1
index match {
case 0 => return s.slice(1, s.length)
case lastIndex => return s.slice(0, s.length()-1)
case _ => { s.slice(0, index) + s.slice(index+1, s.length) }
}
The second clause does not try to match index
with lastIndex
as you would have expected from e.g. Prolog. Instead it matches any value and binds the value to the name lastIndex
, shadowing the previous binding of this variable.
精彩评论