我要提问
ARTICLE DETAIL

资讯详情

前沿编程新知与开发实战干货的深度解读。

扩展方法与隐式转换:programming-scala-book-code-examples 如何优雅地扩展已有类型

扩展方法与隐式转换:programming-scala-book-code-examples 如何优雅地扩展已有类型 扩展方法与隐式转换programming-scala-book-code-examples 如何优雅地扩展已有类型【免费下载链接】programming-scala-book-code-examplesThe code examples used in Programming Scala, 2nd and 3rd Editions (OReilly)项目地址: https://gitcode.com/gh_mirrors/pr/programming-scala-book-code-examples在 Scala 3 中扩展方法Extension Methods与隐式转换Implicit Conversions是两把威力强大的瑞士军刀而 programming-scala-book-code-examples 这个收录了 OReilly《Programming Scala第 3 版》全部代码示例的开源项目恰好把它们用到了极致。无论你是刚接触 Scala 的新手还是想精进类型系统技巧的开发者这套示例都能帮你快速掌握如何在不修改源码的情况下为已有类型赋予新能力。本文将带你逐层拆解其中的核心玩法全程基于真实可运行的源码讲解。为什么要扩展已有类型先从痛点说起日常开发中我们经常遇到这样的困境String、Seq、Int这些别人的类型没有我们想要的方法。传统做法是写一堆静态工具类比如StringUtil.upper(s)调用起来既啰嗦又破坏代码的可读性。Scala 3 给出了更优雅的答案扩展方法能直接假装某个方法本来就属于该类型而隐式转换则能在类型不匹配时自动完成翻译。这个项目里的 contexts 目录就是围绕这些能力组织的一整片试验田。扩展方法入门给类型附加新能力扩展方法的语法非常直观。在 GenericExtensionMethods.scala 中作者给任意Seq添加了一个sortedUnique方法用来排序并去重extension A: Ordering def sortedUnique: Seq[A] if seq.size 0 then seq else val sorted seq.sorted sorted.foldLeft(Vector(sorted.head)) { (vect, a) if vect.last a then vect else vect : a }注意两个细节extension [A: Ordering]表示这是一个泛型扩展方法适用于任意元素类型A前提是存在Ordering[A]排序规则。定义之后你就可以像调用原生方法一样写Seq(3,1,2,1).sortedUnique编译器会自动把它翻译成对扩展方法的调用。这类技巧在函数式编程场景下尤为实用项目中的 fp 与 collections 目录还提供了大量配套示例值得一并阅读。隐式转换类型之间的自动桥接如果说扩展方法是给类型加方法那隐式转换就是给类型换身份。在 Scala 3 中隐式转换通过given Conversion声明见 NewImplicitConversions.scalaimport scala.language.implicitConversions given Conversion[Double,Dollars] d Dollars(d) given Conversion[Double,Percentage] d Percentage(d) val salary Salary(100_000.0, 20.0) // 自动把 Double 转成 Dollars/Percentage这里定义了一个工资计算模型Salary(gross: Dollars, taxes: Percentage)。正常情况下你必须手动构造Dollars(100_000.0)但有了given Conversion直接传100_000.0就会被自动翻译成Dollars。类似的Conversion[Int, Dollars]还展示了如何为不同类型分别注册转换规则。需要提醒的是隐式转换虽然方便但过度使用会降低代码可读性因此 Scala 3 要求显式import scala.language.implicitConversions来声明你清楚自己在做什么。隐式转换的解析顺序就近原则隐式转换不是随机生效的它遵循作用域就近优先的规则。在测试文件 ImplicitConversionResolutionSuite.scala 中作者用 MUnit 编写了完整的验证用例作用域转换规则调用结果scope1导入Foo.*String → Fooscope1(foo)自动转换成功scope2导入scope2.implicits.given新的String → Foo使用最近的转换规则这个测试还揭示了一个趋势Scala 正在逐步淘汰旧的implicit class写法统一改用given Conversion——跟着这套示例学习你不会学到过时的语法。扩展方法的作用域控制按需生效的魔法扩展方法并非全局生效它只在被导入的范围内可用这正是一种精心设计的安全性。在 ExtensionMethodScoping.scala 中可以看到清晰的演示定义在trait T里的扩展方法LOUD必须通过继承该 trait 的对象才能调用定义在object S2里的扩展方法soft必须import S2.soft之后才能使用未导入时直接调用会报编译错误——这正是我们希望看到的可控性。这种机制让团队可以放心地在库中定义扩展方法而不必担心污染使用方的命名空间。扩展方法的高级玩法类型类与自定义操作符用扩展方法实现类型类Type Class类型类Type Class是 Scala 3 最核心的抽象模式之一。在 MonoidTypeClass.scala 中扩展方法被用来为String和Int分别注入combine方法given StringMonoid: Monoid[String]: def unit: String extension (s: String) infix def combine(other: String): String s other这样a.combine(b)和1.combine(2)都能直接调用同一套抽象接口适用于完全不同的类型。更完整的实战案例在 ToJSONTypeClasses.scala——它通过扩展方法为Circle、Rectangle、Triangle等图形类型统一添加toJSON序列化能力堪称面向扩展开放的教科书级示范。自定义操作符让 DSL 更自然扩展方法还可以定义自定义操作符。在 ArrowAssocExtension.scala 中作者定义了~和~~操作符让任意两个值都能轻松组成元组extension [A] (a: A) def ~B: (A, B) (a, b)运行后1 ~ one直接得到(1, one)。这种技巧在构建内部 DSL领域特定语言时非常常用配合 dsls/payroll 目录下的薪资计算示例你能看到扩展方法如何让领域代码读起来像自然语言。扩展字符串插值器写 SQL 也能类型安全扩展方法的应用远不止于此。在 SQLStringInterpolator.scala 中作者通过扩展StringContext实现了一个迷你 SQL 插值器让你写出sqlSELECT name FROM users这样的代码并自动解析出列名和表名——把扩展已有类型的思想玩到了全新的高度。如何在本地运行这些示例这套示例的配套测试非常完善。想要亲手验证扩展方法与隐式转换的行为推荐这样做克隆仓库git clone https://gitcode.com/gh_mirrors/pr/programming-scala-book-code-examples安装sbt构建工具仓库根目录的project配置会自动拉取正确版本的依赖运行sbt test执行全部测试重点观察 contexts 目录下的ImplicitConversionResolutionSuite与GenericExtensionMethodsSuite也可以直接运行sbt console进入 REPL把 src/script/scala/progscala3/contexts/ 下的脚本文件逐行粘进去体验。小提示仓库根目录还提供了check-scripts.sh和check-mains.sh两个辅助脚本可以半自动化地验证所有示例的输出是否符合预期。总结这套示例教会我们的三件事通过 programming-scala-book-code-examples 这个项目你可以一次性掌握 Scala 3 扩展类型能力的完整图景扩展方法让给别人的类型加方法变得像写普通方法一样自然且支持泛型与作用域控制隐式转换given Conversion在类型不匹配时自动翻译但要谨慎使用、就近解析两者与类型类、DSL、字符串插值器结合能组合出极其优雅的库设计。如果你想写出调用方代码最优雅的 Scala 代码contexts 目录下的每个文件都值得反复研读——它们是理解 Scala 3 类型系统设计哲学的最佳入口。【免费下载链接】programming-scala-book-code-examplesThe code examples used in Programming Scala, 2nd and 3rd Editions (OReilly)项目地址: https://gitcode.com/gh_mirrors/pr/programming-scala-book-code-examples创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表