Scala中如何通过嵌套上下文导入隐式类并实现跨层级导出
问题说明
以下跨两层导入隐式类的代码,最后一行无法通过编译:
// 跨两层导入隐式类 object Foo { implicit class IntWithSquare(x: Int) { def square = x*x } } object Bar { import Foo._ println(4.square) // 本行可正常编译运行 } import Bar._ println(5.square) // 本行编译失败
需求为:强制从Bar对象导出其已导入的隐式类,实现目标是将所有隐式定义放在独立文件中,保持Foo对象的业务代码整洁。
普通方法、类型从Foo导入Bar后再对外导出时,可以通过在Bar中重新声明顶层名称的方式解决,参考可正常运行的示例代码:
// 跨两层导入普通定义和类型 object Foo { def someBigFunc(): Int = { 42 } type Word = String } object Bar { import Foo._ val someBigFunc = Foo.someBigFunc _ type Word = Foo.Word } import Bar._ someBigFunc() val w: Word = "word"
解决方案
核心原因:Scala中通过import导入的隐式成员不会被对象自动对外导出,和普通值、类型的处理逻辑一致,必须在Bar内部显式声明要对外暴露的隐式实体,才能在导入Bar._时被隐式解析机制识别。
针对隐式类的导出需求,有两种常用实现方案:
- 方案1:单隐式手动转发
隐式类本质是语法糖,编译后会生成同名的隐式转换方法,直接在Bar内显式声明对应隐式成员,指向Foo中的实现即可,无需重复编写隐式类逻辑:object Bar { import Foo._ // 显式导出对应的隐式转换 implicit val exportIntSquare = Foo.IntWithSquare _ println(4.square) } import Bar._ println(5.square) // 正常编译运行,输出25 - 方案2:多隐式统一托管
如果需要导出的隐式定义较多,手动逐个转发维护成本高,可以将所有隐式定义抽离到独立的trait中托管,让需要导出隐式的对象直接继承该trait,无需逐个手动声明:// 独立文件中存放所有隐式定义,和业务代码完全隔离 trait AllImplicitDefinitions { implicit class IntWithSquare(x: Int) { def square = x*x } } // 业务对象Foo混入隐式trait即可直接使用隐式,本身代码保持整洁 object Foo extends AllImplicitDefinitions { // Foo自身业务逻辑 } // Bar同样混入隐式trait,导入Bar._时可直接获取所有隐式 object Bar extends AllImplicitDefinitions { println(4.square) } import Bar._ println(5.square) // 正常编译运行
补充说明:如果使用Scala 3版本,其
export语法默认也不会导出given(即Scala 2中的implicit)成员,需要显式指定导出隐式,例如全量导出Foo中的隐式可写为export Foo.given _,导出单个隐式可写为export Foo.given IntWithSquare。
内容的提问来源于stack exchange,提问作者Ben Bulent Basaran
相关产品推荐
相关产品推荐

