Scala v2.13.11对pureconfig orElse documentation(页面底部)中的以下代码发出警告:
val csvIntListReader = ConfigReader[String].map(_.split(",").map(_.toInt).toList)
implicit val intListReader = ConfigReader[List[Int]].orElse(csvIntListReader)
case class IntListConf(list: List[Int])
字符串
警告是:
[warn] Implicit definition should have explicit type (inferred pureconfig.ConfigReader[List[Int]])
[warn] implicit val intListReader = ConfigReader[List[Int]].orElse(csvIntListReader)
[warn] ^
型
当我添加推断类型ConfigReader[List[Int]]
时,它编译时没有警告,但我在运行时得到一个NullPointerException
。
这给我提出了以下问题:
1.为什么当我们让编译器推断类型时,这是可行的,但当我们显式提供编译器说它推断的类型时,它却不起作用?
1.有没有一种类型可以显式地赋予intListReader
,使其编译时没有警告,运行时没有错误?
1.如果3是不可能的,那么添加@nowarn
是否“安全”(例如仍然可以使用Scala 3)?
谢谢你的见解。
PS:我的运行时测试也来自文档:
ConfigSource.string("""{ list = [1,2,3] }""").load[IntListConf] ==> Right(IntListConf(List(1, 2, 3)))
型
和/或
ConfigSource.string("""{ list = "4,5,6" }""").load[IntListConf] ==> Right(IntListConf(List(4, 5, 6)))
型
2条答案
按热度按时间ogq8wdun1#
这是一个未记录的未定义行为。
当您这样做时:
字符串
编译器将生成
型
这取决于上下文(在你有它的地方,它是
val
,lazy val
还是def
)将结束:通常,您希望将其解析为:
型
这将使用一些机制来避免在计算隐式的过程中使用
x
。例如,通过使用一些 Package 器或子类型来解包/上转换(例如,在Circe中,您要求使用semiauto导出的Encoder/Decoder,并且通过隐式获得的是一些DerivedEncoder/DerivedDecoder来解包/上投)。这是定义的行为,当你的作用域中的所有隐式定义都被注解时,隐式是如何被解析的。
如果有些人不像这个人会怎么样?
intListReader
时,编译器被询问有关隐式ConfigReader[List[Int]]
的信息intListReader
)的类型计算为ConfigReader[List[Int]]
一般来说,库不应该依赖于这种行为,应该有一些半自动派生为您提供,在Scala(3.x)的未来版本中,这段代码是非法的,所以我建议将其重写为semiauto。
在您的特定情况下,您还可以使用一个技巧,调用与返回的不同的隐式:
型
但是如果它不是一个内置支持的类型(它们不适用于
deriveReader
,因为它只为sealed
和case class
定义),你可以用途:型
3phpmpom2#
当您提供显式类型时,所有内容都以显式方式工作。
这里的
NullPointerException
是由运行时提供的值引起的运行时异常。这意味着配置中提供的值是罪魁祸首。当配置包含空字符串时,您的
ConfigReader
在_.split(",")
上失败。只需在代码中处理
null
的可能性。字符串
这将允许从空字符串到空列表的转换。但当提供的列表包含非整数值时,这仍然会失败。
另外,尽量总是使用显式类型和隐式值,否则你最终会得到一个需要跟踪的推断隐式迷宫。
Scala类型推断的工作原理是,通过返回使用信息,在允许的可能类型中为所提供的值选择类型。
在
implicit
的情况下,Scala编译器希望从提供的类型的可用implicit
值中选择最佳值。你现在应该能看到问题所在了。。当你让编译器决定提供值的类型和补充类型的值时...编译器对此不会很高兴。