【问题标题】:How to know which implicit fails to be resolved?如何知道哪个隐式无法解决?
【发布时间】:2019-09-03 17:54:11
【问题描述】:

我正在尝试从两个具有不同类型和不同顺序的不同字段的案例类创建一个自动适配器。 它有时会起作用。调试并知道哪些隐式无法解决是非常困难的。 当编译器找不到特定的适配器时,我必须开始测试每个所需的隐式并检查哪个失败以及原因。有没有办法标记为什么给定的隐式方法是候选方法并且在尝试解决嵌套隐式时不再存在?

对不起,如果这听起来令人困惑!

private implicit def fromRecordAdapter
  [
  Source, SourceFields <: HList, SourceRecord <: HList, Target, TargetFields <: HList, TargetRecord <: HList,
  SelectedFields <: HList, AddedFields <: HList,
  SourceTakenProduct <: HList, TargetProduct <: HList, CommonRecord <: HList, AddedProduct <: HList,
  AddedRecord <: HList, UnorderedRecord <: HList
  ](
     implicit
     sourceRecord: LabelledGeneric.Aux[Source, SourceRecord]
     , sourceFields: Keys.Aux[SourceRecord, SourceFields]
     , targetRecord: LabelledGeneric.Aux[Target, TargetRecord]
     , recordFields: Keys.Aux[TargetRecord, TargetFields]
     , selectedFields: hlist.Intersection.Aux[SourceFields, TargetFields, SelectedFields]
     , addedFields: hlist.Diff.Aux[TargetFields, SelectedFields, AddedFields]
     , sourceTakenProduct: SelectAll.Aux[SourceRecord, SelectedFields, SourceTakenProduct]
     , targetProduct: SelectAll.Aux[TargetRecord, SelectedFields, TargetProduct]
     , addedProduct: SelectAll.Aux[TargetRecord, AddedFields, AddedProduct]
     , sourceToTargetMapper: TypeMapper[TargetProduct, SourceTakenProduct]
     , addedProductDefault: Lazy[DefaultValue[AddedProduct]]
     , commonRecord: ZipWithKeys.Aux[SelectedFields, TargetProduct, CommonRecord]
     , addedTagger: ZipWithKeys.Aux[AddedFields, AddedProduct, AddedRecord]
     , prepend: Prepend.Aux[CommonRecord, AddedRecord, UnorderedRecord]
     , align: hlist.Align[UnorderedRecord, TargetRecord]
   ): Adapter[Source, Target] = ...

换句话说,我很想知道那个长列表中的哪个参数,编译器停下来说,例如:“该死,sourceToTargetMapper:TypeMapper[TargetProduct, SourceTakenProduct] 没有隐含”

这样我就知道从哪里开始检查了

【问题讨论】:

标签: scala logging implicit shapeless


【解决方案1】:

你可以试试

scalacOptions += "-Xlog-implicits"

如果您尝试显式调用fromRecordAdapter,编译器不会写吗?

def foo(implicit i: Int, b: Boolean, s: String, l: Long): Unit = ()

implicit val int: Int = 1
implicit val bool: Boolean = true

foo
//Error: could not find implicit value for parameter s: String

//Error: not enough arguments for method foo: (implicit i: Int, implicit b: Boolean, implicit s: String, implicit l: Long)Unit.
//Unspecified value parameter s.

【讨论】:

  • 我遇到这种情况,该方法采用隐式,但默认值为 null。所以当实际上没有提供隐式但没有编译器错误时,我完全一无所知。
  • @texasbruce 好吧,情况不同。实际上,这就是不使用具有默认值的隐式参数的原因(有时它被认为是anti-pattern)。最好定义类型类的低优先级实例。
  • @texasbruce 我会尝试gist.github.com/DmytroMitin/e2930223069f5bbb303bb9460b97ae89 不幸的是,这会在运行时打印消息。如果我想让它在编译时工作,宏注释checkImplicits 需要将方法转换为 def 宏和转换方法,并且它的应用程序需要在不同的编译单元中。
  • 我同意你的观点,这不是很安全。事实上,我在使用 Akka 时遇到了这个问题:def !(message: Any)(implicit sender: ActorRef = Actor.noSender): Unit。我创建了一个要混合的特征,忘记声明一个隐式 ActorRef,但没有错误,并且 Akka 使用 noSender 作为发送者,这花了我很长时间来调试......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-07-19
  • 2015-01-11
  • 1970-01-01
  • 1970-01-01
  • 2019-10-12
  • 1970-01-01
  • 2022-06-15
相关资源
最近更新 更多