【问题标题】:Inject methods into existing classes将方法注入现有类
【发布时间】:2010-11-18 09:22:01
【问题描述】:

我想找到一种方法来在 scala 中的某个现有类中定义一个新方法。

比如我觉得asInstanceOf[T]方法名字太长,想换成as[T].

直接的方法可以是:

class WrappedAny(val a: Any) {
  def as[T] = a.asInstanceOf[T]
}

implicit def wrappingAny(a: Any): WrappedAny = new WrappedAny(a)

有没有更自然、代码更少的方法?

另外,当我尝试这个时会发生一件奇怪的事情:

scala> class A

defined class A

scala> implicit def toA(x: Any): A = x

toA: (x: Any)A

scala> toA(1)

控制台挂起。似乎toA(Any) 不应该通过类型检查阶段,并且当它不是隐式时也不能。并且将所有代码放入外部源代码中也会产生同样的问题。这怎么发生的?是编译器(2.8.0版)的bug吗?

【问题讨论】:

    标签: scala


    【解决方案1】:

    您拉皮条Any 的方法在技术上没有任何问题,尽管我认为这通常是不明智的。同样,asInstanceOfisInstanceOf 的名称如此冗长也是有原因的;这是为了阻止您使用它们!几乎可以肯定,有更好的、静态类型安全的方式来做任何你想做的事情。

    关于导致控制台挂起的示例:toA 的声明类型为Any => A,但您将其结果定义为x,其类型为Any,而不是A。这怎么可能编译?好吧,请记住,当出现明显的类型错误时,编译器会四处寻找任何可用的隐式转换来解决问题。在这种情况下,它需要一个隐式转换 Any => A... 并找到一个:toA!所以toA类型检查的原因是因为编译器隐含地将它重新定义为:

    implicit def toA(x: Any): A = toA(x)
    

    ...当您尝试使用它时,这当然会导致无限递归。

    【讨论】:

    • 哇!这真太了不起了。你是怎么想出这个主意的?此外, asInstanceOf[T] 只是一个示例。我只是好奇在一般情况下是否有任何语法糖果。
    • 作为一般规则,如果您的代码中明显存在类型错误但编译器接受它,则说明存在隐式转换......这和它挂起的事实是主要线索:)
    【解决方案2】:

    在第二个示例中,您将Any 传递给必须返回A 的函数。但是,它永远不会返回 A,而是返回您传入的 Any。然后编译器会尝试应用隐式转换,而隐式转换又不会返回 A,而是返回 Any,等等。

    如果你将 toA 定义为不是隐式的,你会得到:

    scala> def toA(x: Any): A = x           
    <console>:6: error: type mismatch;
     found   : Any
     required: A
           def toA(x: Any): A = x
                                ^
    

    【讨论】:

      【解决方案3】:

      碰巧,这已经在 Scala 列表中讨论过了。 pimp my class 模式确实有点冗长,也许有一种方法可以在不引入新关键字的情况下清理语法。

      关于新关键字的一点是,Scala 的目标之一是通过库使语言可扩展,而不是将语言变成一个巨大的想法被子,通过某人的标准“足以添加到语言中”,并且,同时,由于其他想法不够有用和/或不够普遍,因此无法实现。

      无论如何,到目前为止还没有任何进展,而且我还没有听说有任何工作在朝着这个目标前进。欢迎您通过其邮件列表加入社区并为其发展做出贡献。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-07-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多