加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

scala – 隐式定义有多糟糕?

发布时间:2020-12-16 08:59:29 所属栏目:安全 来源:网络整理
导读:我喜欢隐式定义.它们使代码看起来很好,它们使用户觉得某些特性在类只是隐式定义时自然可用.然而,我在考虑JS原型,你基本上可以在你没写的类上定义一个方法.但是如果在下一个版本中,这个类定义了一个具有相同签名并对其行为进行假设的方法,那么你就搞砸了. Sca
我喜欢隐式定义.它们使代码看起来很好,它们使用户觉得某些特性在类只是隐式定义时自然可用.然而,我在考虑JS原型,你基本上可以在你没写的类上定义一个方法.但是如果在下一个版本中,这个类定义了一个具有相同签名并对其行为进行假设的方法,那么你就搞砸了.

Scala的含义使得几乎完全相同,只有一个主要区别:隐式定义是作用域的,因此类的作者不会有通过其他人的代码中的隐式定义注入代码的风险.但是用户的代码怎么样?是否保护他免受课堂上的变化,他是否会加入暗示?

我们考虑一下这段代码:

class HeyMan {
    def hello = println("Hello")
}

object Main extends App {
    val heyMan = new HeyMan

    implicit class ImplicitHeyMan(heyMan: HeyMan) {
        def hello = println("What's up ?")
    }
    heyMan.hello // prints Hello
}

很糟糕,不是吗?对我来说,正确的行为应该是隐式定义总是隐藏真实的定义,以便保护用户代码免受他所调用的API中新方法的显示.

你怎么看 ?有没有办法让它安全或者我们应该停止使用这种方式吗?

解决方法

关于隐式转换的语言行为非常清楚地定义:

if one calls a method m on an object o of a class C,and that class does not support method m,then Scala will look for an implicit conversion from C to something that does support m.

http://docs.scala-lang.org/tutorials/FAQ/finding-implicits.html

换句话说,如果heyMan的(静态已知的)类/特征已经定义了方法,那么隐式转换将永远不会应用于表达式heyMan.hello中的heyMan只有在调用它没有的方法时才尝试hello-implicit转换我们已经定义了.

To me,the correct behaviour should be that the implicit definition always shades the real definition,so that the user code is protected from the apparition of new methods in the API he’s calling into.

不是相反的情况同样如此吗?如果隐式转换确实优先,那么用户将面临他们长期定义的方法的危险,这些方法已经存在了5年,突然被新版本的库依赖中的新隐式转换所掩盖.

与用户对新方法的显式定义优先的情况相比,这种情况似乎更加隐蔽且难以调试.

Is there a way to make it safe or should we stop using implicits this way ?

如果获得隐式行为非常重要,也许您应该使用显式类型强制隐式转换:

object Main extends App {
    val heyMan = new HeyMan

    implicit class ImplicitHeyMan(heyMan: HeyMan) {
        def hello = println("What's up ?")
    }

    heyMan.hello // prints Hello

    val iHeyMan: ImplicitHeyMan // force conversion via implicit
    iHeyMan.hello // prints What's up
}

从评论中的(扩展)对话中,您似乎想要一种方法来检查基础类是否不会通过隐式转换定义您正在使用的方法.

我认为?ukasz在下面的评论是正确的 – 这是你应该在测试中捕获的东西.具体来说,您可以使用ScalaTest’s assertTypeError.只是尝试调用隐式范围之外的方法,它应该无法键入check(并通过测试):

// Should pass only if your implicit isn't in scope,// and the underlying class doesn't define the hello method
assertTypeError("(new HeyMan).hello")

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读