Scala中NestedStrMap类嵌套Map构建及返回类型定义疑问
Scala中实现动态嵌套Map的NestedStrMap类
需求说明
我需要创建一个名为NestedStrMap的Scala类,类签名如下:
final class NestedStrMap[A](list: List[A], first: A => String, rest: (A => String)*)
要在这个类中实现asMap方法,利用first和可变参数rest中的函数,将输入的List[A]构建成嵌套的Map结构。但目前无法确定asMap的返回类型,初始实现因类型不匹配报错:
def asMap = { rest.toList.foldLeft(list.groupBy(first)) { (acc, i) => acc.view.mapValues(l => l.groupBy(i)).toMap // 类型不匹配报错 } }
期望效果
以下是目标使用示例,最终要得到多层嵌套的Map:
case class TestResult(name: String, testType: String, score: Int) val testList = List( TestResult("A", "math", 75), TestResult("B", "math", 80), TestResult("B", "bio", 90), TestResult("C", "history", 50) ) val nestedMap = NestedStrMap(testList, _.name, _.testType) val someMap: Map[String, Map[String, List[TestResult]]] = nestedMap.asMap println(someMap) /* 输出: Map( A -> Map(math -> List(TestResult(A,math,75))), B -> Map(math -> List(TestResult(B,math,80)), bio -> List(TestResult(B,bio,90))), C -> Map(history -> List(TestResult(C,history,50))) ) */
解决方案:可实现,利用递归类型推导
这个需求完全可以实现,核心是让编译器根据rest参数的数量,自动推导嵌套Map的类型。下面分别给出Scala 3和Scala 2的可行实现:
Scala 3 实现(推荐,利用匹配类型)
Scala 3的匹配类型(Match Types)可以直接定义递归的嵌套Map类型,代码简洁且类型推导自动完成:
final class NestedStrMap[A](private val list: List[A], first: A => String, rest: (A => String)*) { // 定义递归的嵌套Map类型:根据函数列表的长度决定嵌套层数 private type NestedMap[Fs <: List[A => String]] = Fs match { case Nil => List[A] case _ :: tail => Map[String, NestedMap[tail]] } def asMap: NestedMap[first :: rest.toList] = { // 递归构建嵌套Map def build[Fs <: List[A => String]](currentList: List[A], fns: Fs): NestedMap[Fs] = fns match { case Nil => currentList case f :: remainingFns => currentList.groupBy(f).view.mapValues { subList => build(subList, remainingFns) }.toMap } build(list, first :: rest.toList) } }
Scala 2 实现(利用隐式类型类)
Scala 2没有匹配类型,需要通过隐式类型类来递归推导嵌套类型:
import scala.language.implicitConversions // 辅助类型类,用于推导嵌套Map类型 trait NestedMapBuilder[A] { type Out def build(list: List[A], fns: List[A => String]): Out } object NestedMapBuilder { // 基础情况:只有第一个函数时,返回Map[String, List[A]] implicit def base[A]: NestedMapBuilder[A] { type Out = Map[String, List[A]] } = new NestedMapBuilder[A] { type Out = Map[String, List[A]] def build(list: List[A], fns: List[A => String]): Out = list.groupBy(fns.head) } // 递归情况:每多一个函数,嵌套一层Map[String, ...] implicit def recursive[A, PrevOut](implicit prev: NestedMapBuilder[A] { type Out = PrevOut }): NestedMapBuilder[A] { type Out = Map[String, PrevOut] } = new NestedMapBuilder[A] { type Out = Map[String, PrevOut] def build(list: List[A], fns: List[A => String]): Out = prev.build(list, fns.tail).view.mapValues(_.groupBy(fns.head)).toMap } } final class NestedStrMap[A](private val list: List[A], first: A => String, rest: (A => String)*) { def asMap(implicit builder: NestedMapBuilder[A]): builder.Out = { builder.build(list, first :: rest.toList) } }
使用时,编译器会自动推导asMap的返回类型,完全符合预期效果。
内容的提问来源于stack exchange,提问作者fungtional
相关产品推荐
相关产品推荐

