我正在尝试支持框架的ID类型的抽象。示例:
object AmINecessary {
case class StringConverter[T](op: String => T)
implicit val toInt = new StringConverter[Int](_.toInt)
implicit val toLong = new StringConverter[Long](_.toLong)
}
class Foo[ID] {
// ID can be String, Long, or Int
import AmINecessary._
// If ID is string, return string, otherwise convert to ID
def getID(id: String)(implicit c: StringConverter[ID] = null): ID = if (c == null) id.asInstanceOf[ID] else c.op(id)
}
然后用作:
val fooString = new Foo[String]
val fooLong = new Foo[Long]
val fooInt = new Foo[Int]
fooString.getID("asdf") // "asdf":String
fooLong.getID("1234") // 1234:Long
fooInt.getID("1234") // 1234:Int
fooInt.getID("asdf") // java.lang.NumberFormatException
这可以按预期工作。我的问题是:
答案 0 :(得分:1)
我认为最好的选择是简单地添加隐式StringConverter[String]
并删除默认的null
值。
这样,您的fooString
可以在不冒任何其他类型ClassCastException
的情况下工作。
object AmINecessary {
case class StringConverter[T](op: String => T)
implicit val toInt = new StringConverter[Int](_.toInt)
implicit val toLong = new StringConverter[Long](_.toLong)
implicit val idConverter = new StringConverter[String](identity)
}
class Foo[ID] {
import AmINecessary.StringConverter
def getID(id: String)(implicit c: StringConverter[ID]): ID = c.op(id)
}
关于您的问题2,类型类方法不是非常必要(但请注意,此处没有隐式转换)。你也可以这样做:
abstract class Foo[ID] {
def getID(id: String): ID
}
class FooInt extends Foo[Int] {
def getID(id: String) = id.toInt
}
class FooLong extends Foo[Long] {
def getID(id: String) = id.toLong
}
class FooString extends Foo[String] {
def getID(id: String) = id
}
答案 1 :(得分:0)
1)关于隐式默认为null,你可以:
object Unsafe {
implicit val toT[T] = new StringConverter[T](_.asInstanceOf[T])
}
2)这似乎不是一个好主意。首先,因为你隐藏了asInstanceOf,这是不安全的操作(潜在的运行时异常)。其次,转换越明确 - 越好。
如果您期望进行一些复杂的转换 - 最好从getID方法返回选项:
def getId[T](id: String)(converter: Option[StringConverter] = None) = converter.map(_.op(id))
但是,默认参数也不是最好的方法。我会坚持编译时错误,要求用户编写自己的转换器或明确地执行asInstanceOf
。
在你的具体情况中asInstanceOf
没有多大意义,因为它唯一适用的类型是String,如getId[String]
,那么调用getId
的重点是什么呢? / p>