Scala带值条件的隐式类型转换编译报错求助
问题分析与解决
问题描述
需求是根据字符串长度转换类型:长度≤10转Int,否则转BigDecimal。用类型类实现的代码如下:
trait Number case class IntNumber(ch: String) extends Number case class BigDecNumber(ch: String) extends Number def wrap(ch: String): Number = ch match { case c if (c.length <= 10) => IntNumber(c) case c if (c.length > 10) => BigDecNumber(c) } trait TypeTransformer[A <: Number, B] { def toDigit(ch: A): B } object transformer { def transform[A <: Number, B](in: A)(implicit t: TypeTransformer[A, B]): B = t.toDigit(in) implicit val stringToInt: TypeTransformer[IntNumber, Int] = (number: IntNumber) => number.ch.toInt implicit val stringToBigDecimal: TypeTransformer[BigDecNumber, BigDecimal] = (number: BigDecNumber) => BigDecimal(number.ch) }
调用transformer.transform(wrap("1231547234133123"))时编译报错:No implicits found for parameter TypeTransformer[Number, B_]。
问题原因
wrap方法返回的是父类型Number,但你定义的TypeTransformer隐式实例只针对IntNumber和BigDecNumber这两个子类型。Scala是静态类型语言,编译期无法确定wrap返回的具体子类型,因此找不到对应Number类型的隐式转换实例,导致报错。
解决方案
需要让编译器在调用transform时能明确识别具体子类型,以下是两种实用解决方法:
方法1:调用处用模式匹配拆分具体类型
把wrap的结果通过模式匹配分到具体子类型后,再分别调用transform:
val num = wrap("1231547234133123") val result = num match { case i: IntNumber => transformer.transform(i) case b: BigDecNumber => transformer.transform(b) }
方法2:修改wrap返回类型为Either
让wrap返回Either[IntNumber, BigDecNumber],保留编译期类型信息:
def wrap(ch: String): Either[IntNumber, BigDecNumber] = if (ch.length <= 10) Left(IntNumber(ch)) else Right(BigDecNumber(ch)) // 调用方式 wrap("1231547234133123").fold(transformer.transform, transformer.transform)
内容的提问来源于stack exchange,提问作者Jelly
相关产品推荐
相关产品推荐

