能否让子特质从另一特质继承类参数?基于Circe解码的代码复用方案咨询
解决Circe解码代码重复的问题
你遇到的“A is not a class”错误,本质是因为Circe的deriveDecoder是编译时宏,它需要在编译阶段明确知道要解码的具体类型,而你定义的JsonDecoding[A]特质中,A是抽象类型参数,编译器无法为这个抽象类型生成解码器代码。
下面给你几个可行的优化方案,按简洁度排序:
方案1:全局隐式解码器生成器
最简洁的方式是定义一个全局隐式方法,自动为任意类型生成snakeCase命名的解码器,需要的地方直接导入即可,完全消除重复代码:
import io.circe.derivation.deriveDecoder import io.circe.derivation.renaming.snakeCase import io.circe.Decoder object SnakeCodecs { // 隐式方法:自动为任意类型A生成snakeCase解码器 implicit def deriveSnakeDecoder[A]: Decoder[A] = deriveDecoder[A](snakeCase) }
然后在你的Getter类中导入使用:
import io.circe.parser.decode import io.circe.{Decoder, Error} class JSONGetter extends Getter[MyClass] { import SnakeCodecs._ // 这里会自动获取Decoder[MyClass]的隐式实例,无需手动定义 // 你的解析代码... }
方案2:用抽象类代替特质
如果希望每个Getter类绑定自己的解码类型,用抽象类代替特质更稳妥——抽象类的类型参数在子类继承时会被具体化,编译器能为具体类型生成解码器:
import io.circe.derivation.deriveDecoder import io.circe.derivation.renaming.snakeCase import io.circe.Decoder abstract class JsonDecoding[A] { implicit val decoder: Decoder[A] = deriveDecoder[A](snakeCase) }
然后你的Getter类可以这样写:
class JSONGetter extends Getter[MyClass] with JsonDecoding[MyClass] { // 解析代码... }
编译可以正常通过,因为MyClass是具体类型,编译器能生成对应的解码器。
方案3:特质+抽象类型成员
如果坚持要用特质,可以把类型参数换成抽象类型成员,让子类明确指定具体类型:
import io.circe.derivation.deriveDecoder import io.circe.derivation.renaming.snakeCase import io.circe.Decoder trait JsonDecoding { type A implicit val decoder: Decoder[A] = deriveDecoder[A](snakeCase) }
子类实现时指定类型:
class JSONGetter extends Getter[MyClass] with JsonDecoding { override type A = MyClass // 解析代码... }
关于子特质继承类参数的问题
在Scala 2中,特质本身不能拥有构造参数,所以无法直接“继承”另一个类的构造参数,但可以通过两种方式间接实现类似效果:
- 自类型注解:在特质中用
this: 父类类型 =>的语法,限定特质只能混入继承了该父类的类中,这样特质就能访问父类的成员(包括构造参数初始化的成员)。 - Scala 3构造参数支持:如果使用Scala 3,特质可以拥有构造参数,此时可以像类一样传递参数,甚至复用父类的构造参数逻辑。
举个Scala 2自类型的例子:
class BaseService(val apiKey: String) trait Logging { this: BaseService => // 可以访问父类的apiKey def log(message: String): Unit = println(s"[$apiKey] $message") } class UserService(apiKey: String) extends BaseService(apiKey) with Logging { def fetchUser(): Unit = { log("Fetching user...") // 业务逻辑 } }
内容的提问来源于stack exchange,提问作者CL40
相关产品推荐
相关产品推荐

