如何在Scala代码库中强制多Column对象场景仅使用Seq集合类型?
强制使用
Seq[Column]的最佳实现方案 方案1:定义专用类型别名+统一构造入口(改造成本最低,适合内部项目)
首先在Column伴生对象中定义全局统一的多Column集合类型,替换所有散写的Seq[Column]:
trait Column { def att1: String def att2: String = "b" } object Column { // 全局统一的多Column集合类型,所有场景必须使用该类型 type ColSeq = Seq[Column] // 统一的多Column构造入口,禁止外部自行用其他集合类型构造多Column集合 def colSeq(cols: Column*): ColSeq = cols.toSeq // 修复原apply方法的栈溢出问题:原写法att1赋值自身会递归初始化报错 def apply(name: String): Column = new Column { override val att1: String = name } }
要求项目中所有涉及多Column的参数、返回值、变量定义都必须使用Column.ColSeq类型,不允许直接声明Seq[Column]或者其他集合类型。后续如果需要调整底层集合实现,只需要修改ColSeq的别名定义即可,不需要全量改动业务代码。
方案2:自定义编译期检查规则(强制度最高,完全避免人工疏漏)
如果需要从编译层面彻底杜绝误用其他集合类型,可以自定义Scalafix或者WartRemover检查规则:
- 配置规则匹配所有类型为
Set[Column]、Array[Column]、List[Column](如果要求仅使用上层Seq抽象而非具体实现类)等不符合要求的集合类型 - 将规则加入编译流程,匹配到不符合要求的类型直接抛出编译错误,提示必须使用
Column.ColSeq类型 - 可以配合sbt的
scalacOptions配置,将相关警告升级为错误,避免漏过问题代码
方案3:值类封装(完全屏蔽底层集合,适合公共SDK场景)
如果是对外提供的公共库,需要更强的约束,可以用无额外性能开销的值类封装底层集合:
// 值类封装,运行时无额外装箱成本 final class ColSeq private (val underlying: Seq[Column]) extends AnyVal { // 按需暴露Seq的常用操作,返回值仍然为ColSeq类型,保证类型一致性 def map(f: Column => Column): ColSeq = new ColSeq(underlying.map(f)) def filter(p: Column => Boolean): ColSeq = new ColSeq(underlying.filter(p)) def ++(other: ColSeq): ColSeq = new ColSeq(underlying ++ other.underlying) def head: Column = underlying.head // 其他业务需要的方法按需扩展 } object ColSeq { // 唯一构造入口,只允许从Column可变参数构造 def apply(cols: Column*): ColSeq = new ColSeq(cols.toSeq) }
这种方案下业务方根本不可能接触到其他集合类型,从根源上避免了误用Set等不符合要求的集合。
配套保障措施
- 将多Column集合必须使用规定类型的要求加入代码规范,作为代码审查的必查项
- 在IDE中添加自定义代码检查规则,遇到不符合要求的类型直接标红提示,提前发现问题
内容的提问来源于stack exchange,提问作者Prassi
相关产品推荐
相关产品推荐

