【发布时间】:2012-04-15 09:12:50
【问题描述】:
编辑
好的,@Drexin 提出了一个很好的观点:使用隐式转换器时失去类型安全/令人惊讶的结果。
如果不发生与 PreDef 隐式冲突的不太常见的转换呢?例如,我正在使用 Scala 中的 JodaTime(伟大的项目!)。在定义了我的隐式的同一个控制器包对象中,我有一个类型别名:
type JodaTime = org.joda.time.DateTime
以及将 JodaTime 转换为 Long 的隐式(对于构建在 ScalaQuery 之上的 DAL,其中日期存储为 Long)
implicit def joda2Long(d: JodaTime) = d.getMillis
这里 PreDef 和我的控制器包隐式之间不存在歧义,并且控制器隐式不会过滤到 DAL 中,因为它在不同的包范围内。所以当我这样做时
dao.getHeadlines(articleType, Some(jodaDate))
IMO 安全地为我完成了到 Long 的隐式转换,并且鉴于大量使用基于日期的查询,我节省了一些样板文件。
同样,对于 str2Int 转换,控制器层接收 servlet URI 参数作为 String -> String。在很多情况下,URI 包含数字字符串,因此当我过滤路由以确定字符串是否为 Int 时,我不想每次都使用 stringVal.toInt;相反,如果正则表达式通过,让我隐式将字符串值转换为 Int 。总而言之,它看起来像:
implicit def str2Int(s: String) = s.toInt
get( """/([0-9]+)""".r ) {
show(captures(0)) // captures(0) is String
}
def show(id: Int) = {...}
在上述上下文中,这些隐式转换的有效用例,还是更多,总是显式的?如果是后者,那么什么是有效的隐式转换用例?
原创
在 package 对象 中,我定义了一些隐式转换,其中一个是简单的 String 到 Int:
implicit def str2Int(s: String) = s.toInt
通常这很好用,接受 Int 参数但接收 String 的方法会转换为 Int,返回类型设置为 Int 但实际返回值是 String 的方法也是如此。
太好了,现在在某些情况下,编译器会出现可怕的隐含歧义:
对象 Predef 类型 (x: String) 中的两个方法 augmentString scala.collection.immutable.StringOps 和方法 str2Int(s: String) Int 是从 java.lang.String 到 ?{val 的可能转换函数 toInt: ?}
我知道发生这种情况的情况是尝试进行手动内联 String 到 Int 的转换。例如val i = "10".toInt
我的解决方法/技巧是创建一个 asInt 帮助器以及包对象中的隐式:def asInt(i: Int) = i 并用作 asInt("10")
那么,隐含的最佳实践是隐含的(即通过燃烧来学习),还是有一些指导方针可以遵循,以免陷入自己制造的陷阱?换句话说,是否应该避免简单、常见的隐式转换,而只使用要转换的类型唯一的地方? (即永远不会遇到歧义陷阱)
感谢您的反馈,隐式非常棒......当它们按预期工作时 ;-)
【问题讨论】:
-
当您在范围内进行隐式转换时,为什么要调用
"10".toInt?您应该改为"10": Int并让隐式转换处理它。 (但我同意 drexin 的观点,一般来说这不是一个很好的隐含范围。) -
我没有调用“10”.toInt,就是一个例子。我被咬的地方是 new JodaTime().toString("yyyy").toInt。我不知道 re:"10": Int 语法,很高兴知道。我编辑了我的答案以显示使用隐式的上下文
-
您的问题现在不包含问题。您能否再次尝试编辑以说明您遇到的问题?
-
隐含还是不隐含,这是个问题。我的编辑更多地显示了我使用隐式转换的上下文。到目前为止的回复是,不要太明确,所以我想知道隐含的“有效”用例是什么?编辑我的问题以反映这一点
-
@virtualeyes 添加方法的隐式转换是可以的(而且是不可避免的)。隐式转换到转换类型充其量是危险的,应该避免。简单来说,
JavaConversions不好,JavaConverters好。它们也可以与类似构建器的模式一起使用,例如在 ScalaQuery 中,但实际上,这是另一个问题。不要改变问题,提出一个新问题。它是免费的。
标签: scala conflict implicit-conversion