Scala 不明确的隐式值是我们希望在编译时使错误存在的唯一方法吗 trait Foo 特征条扩展了Foo def doStuff[T
在这个(和大多数其他)实例中,一个简单的类型类比一个类型不平等测试要好 可能想要排除Scala 不明确的隐式值是我们希望在编译时使错误存在的唯一方法吗 trait Foo 特征条扩展了Foo def doStuff[T,scala,type-safety,shapeless,Scala,Type Safety,Shapeless,在这个(和大多数其他)实例中,一个简单的类型类比一个类型不平等测试要好 可能想要排除Foo的原因是Bar(及其同级)有一些Foo缺少的属性。如果是这种情况,那么您应该创建一个类型类来捕获这些属性,并将其作为doStuff的类型参数的要求。您可以使用Scala的@implicitNotFound注释,使编译器错误消息在需要时更易于理解不符合要求 def typeSafeSum[T <: Nat, W <: Nat, R <: Nat](x: T, y: W) (
Foo
的原因是Bar
(及其同级)有一些Foo
缺少的属性。如果是这种情况,那么您应该创建一个类型类来捕获这些属性,并将其作为doStuff
的类型参数的要求。您可以使用Scala的@implicitNotFound
注释,使编译器错误消息在需要时更易于理解不符合要求
def typeSafeSum[T <: Nat, W <: Nat, R <: Nat](x: T, y: W)
(implicit sum: Sum.Aux[T, W, R], error: R =:!= _7) = x
typeSafeSum(_3, _4)
@annotation.implicitNotFound(msg=“没有${T}的道具实例”)
特质道具[T]{
def wibble(t:t):双倍
}
特色食品
//请注意,Foo没有道具实例。。。
特征条扩展了Foo
对象栏{
//酒吧道具实例
隐式def-barProps:Props[Bar]=新的Props[Bar]{
def接线(t:Bar):双精度=23.0
}
}
def doStuff[T doStuff(新Foo{})
:11:错误:没有Foo的道具实例
多斯塔夫(新富)
^
scala>doStuff(新条{})
res1:Double=23.0
如果没有任何此类属性将Foo
与Bar
区分开来,那么您应该质疑您的假设,即首先需要从doStuff
中排除Foo
如果您在项目中使用shapeless,我会很高兴,但您应该使用
=!:=
(以及Scala自己的=:=
)作为最后的手段,如果有的话。另一种方法,您可以对doStuff
方法施加约束,使用magnet模式,它只是增强了typeclass,例如:
@annotation.implicitNotFound(msg = "No Props instance for ${T}")
trait Props[T] {
def wibble(t: T): Double
}
trait Foo
// Note no Props instance for Foo ...
trait Bar extends Foo
object Bar {
// Props instance for Bar
implicit def barProps: Props[Bar] = new Props[Bar] {
def wibble(t: Bar): Double = 23.0
}
}
def doStuff[T <: Foo](t: T)(implicit props: Props[T]) = props.wibble(t)
scala> doStuff(new Foo {})
<console>:11: error: No Props instance for Foo
doStuff(new Foo {})
^
scala> doStuff(new Bar {})
res1: Double = 23.0
这种情况下的区别在于,您无法添加隐式NotFound注释以获得更好的编译时错误消息,您将得到一个简单的类型不匹配,如:
trait Foo
trait Bar
object DoStuff {
def doStuff[T](value: StuffMagnet[T]): Unit = value()
}
trait StuffMagnet[T] {
def apply(): Unit
}
object StuffMagnet {
implicit def forFoo(foo: Foo): StuffMagnet[Foo] =
new StuffMagnet[Foo] {
def apply(): Unit = ()
}
}
在另一个问题中,我发布了一个答案,解决了获得更好的错误消息的问题: 代码如下:
Test.scala:20: error: type mismatch;
found : Test.Bar
required: Test.StuffMagnet[?]
DoStuff.doStuff(new Bar {})
^
one error found
现在您得到了错误消息error:无法证明Foo=!=Foo
:
@annotation.implicitNotFound(msg = "Cannot prove that ${A} =!= ${B}.")
trait =!=[A,B]
object =!= {
class Impl[A, B]
object Impl {
implicit def neq[A, B] : A Impl B = null
implicit def neqAmbig1[A] : A Impl A = null
implicit def neqAmbig2[A] : A Impl A = null
}
implicit def foo[A,B]( implicit e: A Impl B ): A =!= B = null
}
def doStuff[T抱歉回复太晚,我刚刚从Shapess编辑了NAT示例,我如何自定义此错误消息?因为没有@annotation.ambiguousImplicit内容,这似乎是一个完全不同的问题。通常,礼仪是每个…问题一个问题;-)可能值得添加到Shapess中…您能发送一份PR I吗我的方向?
@annotation.implicitNotFound(msg = "Cannot prove that ${A} =!= ${B}.")
trait =!=[A,B]
object =!= {
class Impl[A, B]
object Impl {
implicit def neq[A, B] : A Impl B = null
implicit def neqAmbig1[A] : A Impl A = null
implicit def neqAmbig2[A] : A Impl A = null
}
implicit def foo[A,B]( implicit e: A Impl B ): A =!= B = null
}
def doStuff[T <: Foo](x: T)(implicit ev: T =!= Foo) = x
doStuff(new Foo{}) // error: Cannot prove that Foo =!= Foo
doStuff(new Bar)// successful