尝试使用Miles Sabin的this技巧来创建一个只接受一组预定义types
参数的函数。
val bool = Boolean
val timestamp = new Timestamp(date.getTime())
val str = "My String"
然后跟随应该在编译时传递
takeValue(bool)
takeValue(timestamp)
takeValue(str)
但是
如果takeValue
takeValue(someIntValue)
的{{1}}未定义,则implicit
type
的{{1}}将失败。此失败将在编译时发生。
Int
然后
trait MyConv[K] { type V; def convert: AnyRef => V }
def iMakeConv[V0](con: AnyRef => V0) = new MyConv[con.type] {
override type V = V0
val convert = con
}
def takeValue(value:AnyRef)(implicit conv :MyConv[value.type]) : \/[Throwable,conv.V] = \/.fromTryCatch(conv.convert(value))
然后我希望implicit val strAny = iMakeConv((x:Any) => x.toString)
在编译时工作但takeValue(str)
在编译时失败,因为没有为它定义任何适当的takeValue(someIntValue)
。基本上希望限制(在编译时)implicit
types
的类型可以为其他人带来和失败。
当然,我在这里做错了,因为在打电话时
takeValue
它在编译时抛出
takeValue("string")
答案 0 :(得分:5)
.type
的含义经常被误解。类型value.type
是一种只有一个值的类型 - value
。即使知道value
为String
,value.type
也不是String
,但只有一个String
- value
。
因此,即使有MyConv[value.type]
可用,代码也会尝试查找MyConv[String]
,但都不存在。
让takeValue
使用类型参数:
def takeValue[T](value: T)(implicit conv: MyConv[T]) : \/[Throwable, conv.V] = \/.fromTryCatch(conv.convert(value))
或者选择MyConv
逆变的类型参数:
trait MyConv[-K] { type V; def convert: AnyRef => V }
如果MyConv[T]
是value.type
的子类型,则可以使用T
。
您还需要一个不同的MyConv
和iMakeConv
:
trait MyConv[K] { type V; def convert: K => V }
def iMakeConv[K, V0](con: K => V0) = new MyConv[K] {
override type V = V0
val convert = con
}