Scala隐式转换问题

时间:2010-10-06 19:08:40

标签: scala dsl

我正在努力解决Scala隐式转换问题。以下代码段说明了我的问题:

import org.junit.{ Test, Before, After };

class ImplicitsTest {

    implicit def toStringWrapper(str: String) = new StringWrapper(str);

    @Test
    def test(){
        val res1: Predicate = "str" startsWith "other";
    }

}

class StringWrapper(str: String){

    def startsWith(other: String): Predicate = null;

}

trait Predicate

如何通过隐式转换toStringWrapper强制将字符串文字“str”转换为startsWith返回Predicate而不是Boolean?

代码示例无法编译。我知道String已经有一个startsWith方法,我只想使用另一个方法,我认为使用隐式转换可能是一种方法。

2 个答案:

答案 0 :(得分:12)

很明显,Scala不会让你在没有注意的情况下偷偷替换替换方法 - 如果你在一个类上调用一个方法,并且该类有这个方法,那就是你得到的方法调用。否则可能会引起各种混乱。

这给你留下了另外两个选择: (1)重命名方法 (2)添加特定方法进行转换。

第二种方法的工作原理如下:您定义了一个既包含您想要的方法又包含返回自身的唯一命名方法的类,如果您希望能够将该类从该类隐式转换回字符串使用自定义项目,如原始字符串(就好像它有扩展字符串):

object ImplicitExample {
  class CustomString(s: String) {
    def original = s
    def custom = this
    def startsWith(other: String): Int = if (s.startsWith(other)) 1 else 0
  }
  implicit def string_to_custom(s: String) = new CustomString(s)
  implicit def custom_to_string(c: CustomString) = c.original

  def test = {
    println("This".custom.startsWith("Thi"))
    println("This".custom.length())
  }
}

scala> ImplicitExample.test
1
4

scala> 

答案 1 :(得分:2)

仅当接收方不包含被调用的方法或表达式的类型与预期类型不同时,才会在Scala中触发隐式转换。

由于上面的String对象包含方法startsWith,因此不会触发隐式转换。但是,编译器会检查右手表达式"str".startsWith("other");(即Boolean)的类型是否可以转换为Predicate。由于范围内没有这种隐式转换,因此会报告错误。

另请注意,隐式转换必须明确无误。例如,您可能尝试使用隐式转换覆盖其他一些方法的Scala字符串行为。 Java String对象不是Scala序列(Seq),这意味着它们没有sorted等方法,它返回序列的排序版本。如果你在字符串上调用它:

scala> "string" sorted
res1: String = ginrst

这是有效的,因为Predef对象中定义的隐式转换会被触发。请注意,提供自己的隐式转换会导致错误:

scala> implicit def wrap(s: String) = new { def sorted = "Hi!" }
wrap: (s: String)java.lang.Object{def sorted: java.lang.String}

scala> "string" sorted
<console>:7: error: type mismatch;
 found   : java.lang.String
 required: ?{val sorted: ?}
 Note that implicit conversions are not applicable because they are ambiguous:
 ...