【问题标题】:Scala implicit conversion problemScala隐式转换问题
【发布时间】:2010-10-06 19:08:40
【问题描述】:

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

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 方法,我只是想使用一个不同的方法,我认为使用隐式转换可能是一种方法。

【问题讨论】:

    标签: scala dsl


    【解决方案1】:

    值得庆幸的是,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> 
    

    【讨论】:

    • 我喜欢为this 提供别名以避免第二个临时对象的模式。
    【解决方案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:
     ...
    

    【讨论】:

      猜你喜欢
      • 2019-04-01
      • 2012-01-02
      • 1970-01-01
      • 2011-08-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-15
      相关资源
      最近更新 更多