如何定义隐式“后备”?

问题描述 投票:0回答:2

考虑一个

tapir.Codec
对象(这就是我遇到这个问题的方式,但我认为它与貘具体没有太大关系,它只是一般来说隐式解析优先级),它定义了一堆编解码器基本类型,如
Codec.long
Codec.int

我试图定义一种“后备”编解码器,可以在找不到标准编解码器时使用(IRL,类型比仅仅

T
更具体,但实际实现在这里并不重要):

implicit def fallbackCodec[T]: Codec[String, T, PlainText] = ??? 

但我不知道该定义在哪里。 我尝试将它添加到我正在扩展的特征之一,或者添加到它自己的特征中,由其他特征扩展,或者添加到它自己的对象中,然后在调用站点导入

Fallback._
...

无论我做什么,

in(path[Foo]("foo"))
都工作得很好,但是
in(path[Long]("id"))
also最终使用我的后备编解码器而不是
Codec.long

我在想,由于标准编解码器是在伴随对象中定义的,因此它们会胜过我的自定义定义,但看起来情况并非如此。我是否缺少一些技巧来让它达到我想要的效果?

scala implicit
2个回答
0
投票

好吧,我想,我找到了一个解决方案,将其留在这里,以防其他人发现它有帮助。 这似乎有效:

trait FallbackCodecs { 
   implicit def plaintextCodec[T]: Codec[String, T, TextPlain] = ???
}

trait DefaultCodecs extends FallbackCodecs { 
   implicit def defaultCodec[T](implicit c: Lazy[Codec[String, T, TextPlain]]) = c.value
}

class FooBar extends DefaultCodecs { 
    def foo[T](implicit c: Codec[String, T, TextPlain]) = println(c)

    foo[Int] // Codec.int
    foo[Foo] // plaintextCodec
 }

另一种可能性,也有效,但不必定义

defaultCodec
并具有额外的特征,那就是显式地
import sttp.tapir.Codec._
FooBar

它有点脆弱,因为如果 FooBar 的作者忘记添加显式导入,它将编译,并用后备默默地替换所有编解码器。此外,它还会生成“未使用的导入”警告。


0
投票

您可以使用

shapeless.LowPriority

//libraryDependencies += "com.chuusai" %% "shapeless" % "2.3.10"

implicit def fallbackCodec[T](implicit lowPriority: LowPriority): Codec[String, T, TextPlain] = ???
© www.soinside.com 2019 - 2024. All rights reserved.