vir*_*yes 2 scala conflict implicit-conversion
编辑
好了,@ Drexin提出了一个很好的重点:使用隐式转换器时类型安全性/惊人结果的丢失.
不太常见的转换怎么样,与PreDef冲突的冲突不会发生?例如,我正在使用Scala中的JodaTime(伟大的项目!).在我的implicits定义的同一个控制器包对象中,我有一个类型别名:
type JodaTime = org.joda.time.DateTime
Run Code Online (Sandbox Code Playgroud)
以及将JodaTime转换为Long的隐式(对于在ScalaQuery之上构建的DAL,其中日期存储为Long)
implicit def joda2Long(d: JodaTime) = d.getMillis
Run Code Online (Sandbox Code Playgroud)
这里PreDef和我的控制器包含义之间不存在歧义,并且控制器含义不会过滤到DAL,因为它在不同的包范围内.所以,当我这样做
dao.getHeadlines(articleType, Some(jodaDate))
Run Code Online (Sandbox Code Playgroud)
对我,IMO,安全地进行了对Long的隐式转换,并且鉴于基于日期的查询被大量使用,我节省了一些样板.
类似地,对于str2Int转换,控制器层接收servlet URI参数作为String - > String.在许多情况下,URI然后包含数字字符串,所以当我过滤路由以确定String是否是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) = {...}
Run Code Online (Sandbox Code Playgroud)
在上面的上下文中,这些用于隐式转换的有效用例,还是更多,总是明确的?如果是后者,那么什么是有效的隐式转换用例?
ORIGINAL
在一个包对象中,我定义了一些隐式转换,其中一个是Int的简单String:
implicit def str2Int(s: String) = s.toInt
Run Code Online (Sandbox Code Playgroud)
通常这样工作正常,采用Int param但接收String的方法转换为Int,返回类型设置为Int的方法也是如此,但实际返回的值是String.
很好,现在在某些情况下,编译器错误与可怕的模糊隐含:
对象中的方法augmentString类型为(x:String)的predef scala.collection.immutable.StringOps和方法str2Int(s:String)Int是可能的转换函数,从java.lang.String到?{val toInt:?}
我知道这种情况发生的情况是在尝试手动内联String-to-Int转换时.例如,val i = "10".toInt
我的解决方法/ hack一直在创建一个asInt帮助器以及包对象中的implicits:def asInt(i: Int) = i并用作,asInt("10")
那么,隐含的隐含最佳实践(即通过烧毁来学习),还是有一些指导方针可以遵循,以免陷入自己制造的陷阱?换句话说,应该避免简单,常见的隐式转换,并且只使用转换类型唯一的地方吗?(即永远不会遇到模棱两可的陷阱)
感谢您的反馈,暗示很棒......当他们按预期工作时;-)
我想你在这里混合了两个不同的用例.
在第一种情况下,在功能相同的情况下,您使用隐式转换来隐藏不同类之间的任意区别(或任意对你).在JodaTime以Long隐式转换适合这一类; 它可能是安全的,而且很可能是一个好主意.我可能会使用enrich-my-library模式,然后写
class JodaGivesMS(jt: JodaTime) { def ms = jt.getMillis }
implicit def joda_can_give_ms(jt: JodaTime) = new JodaGivesMS(jt)
Run Code Online (Sandbox Code Playgroud)
并.ms在每次通话时使用,只是为了明确.原因是这里的单位很重要(毫秒不是微秒不是毫秒不是毫米,但都可以表示为整数),而且在大多数情况下,我宁愿留下一些单位在界面上的记录. getMillis每次都要输入一口,但ms也不是太糟糕.尽管如此,转换仍然是合理的(如果对于可能在未来几年内修改代码的人(包括您)进行详细记录).
然而,在第二种情况下,您在一种非常常见的类型与另一种类型之间执行不可靠的转换.没错,你只是在有限的环境中做到这一点,但这种转变仍然容易逃脱并导致问题(例外或类型不是你的意思).相反,您应该编写正确处理转换所需的那些方便例程,并在任何地方使用它们.例如,假设您有一个您希望为"是","否"或整数的字段.你可能有类似的东西
val Rint = """(\d+)""".r
s match {
case "yes" => println("Joy!")
case "no" => println("Woe!")
case Rint(i) => println("The magic number is "+i.toInt)
case _ => println("I cannot begin to describe how calamitous this is")
}
Run Code Online (Sandbox Code Playgroud)
但是这段代码是错误的,因为"12414321431243".toInt抛出异常,当你真正想要的是说情况是灾难性的.相反,您应该编写匹配正确的代码:
case object Rint {
val Reg = """([-]\d+)""".r
def unapply(s: String): Option[Int] = s match {
case Reg(si) =>
try { Some(si.toInt) }
catch { case nfe: NumberFormatException => None }
case _ => None
}
}
Run Code Online (Sandbox Code Playgroud)
而是使用它.现在不是执行风险和隐性从转换String到Int,当你执行一个匹配它都将得到妥善处理,无论是正则表达式匹配(避免抛出和捕获坏解析异常桩)外,即使正则表达式经过处理.
如果你有一个同时包含字符串和int表示的东西,创建一个新类,然后如果你不想使用该对象(你知道可以安全地使用)继续重复一个方法,那么就可以对它们进行隐式转换呼叫并不真正提供任何照明.
我尝试不要隐式转换任何东西只是为了将它从一种类型转换为另一种类型,但仅限于pimp我的库模式.将String传递给接受Int的函数时,可能会有点混乱.同样存在类型安全性的巨大损失.如果你将一个字符串传递给一个错误地接受Int的函数,那么编译器就无法检测到它,因为它假定你想要这样做.所以总是明确地进行类型转换,并且只使用隐式转换来扩展类.
编辑:
要回答您更新的问题:为了便于阅读,请使用显式getMillis.在我看来,有效的implicits用例是"pimp my library",视图/上下文边界,类型类,清单,构建器......但是不要太懒,不能写一个方法的显式调用.
| 归档时间: |
|
| 查看次数: |
2894 次 |
| 最近记录: |