Scala 隐式转换问题

3

我遇到了一个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返回谓词而不是布尔值?

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

2个回答

12

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

这留下了两个选项: (1)重命名该方法 (2)添加一个特定的方法来进行转换。

第二种方法的工作方式如下:您定义一个类,该类具有您想要的方法和一个唯一命名的返回自身的方法,并且如果您想要像原始字符串一样使用自定义项(就好像它扩展了String)可以选择将该类隐式转换回字符串:

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
我喜欢提供一个别名来避免第二个临时对象的模式。 - retronym

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:
 ...

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接