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