开发者

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") returns bc
  • takeAllExcept(1, "abc") returns ac
  • takeAllExcept(2, "abc") returns ab

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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜