Scala 的缺省参数值 (default parameter value) 在 class 文件中是如何实现的?

Scala 的缺省参数值 (default parameter value) 在 class 文件中是如何实现的?

Scala 支持 缺省参数值,那么这一特性在 class 文件中是如何做到的呢?本文对此进行介绍。

结论

如果函数 f(...) 中用到了缺省参数值,那么

  • class 文件中会为每一个缺省值生成可以提供这个值的函数,函数名看起来是 f$default$N() 这种格式 (N 表示这个参数的位置,从 1 开始计算)
  • class 文件中,调用方会先调用 f$default$N() 这样的函数把缺省值填好,然后再对 f(...) 进行普通的函数调用

代码

我们用以下的 Scala 代码来进行探索(请将代码保存为 A.Scala

Scala 复制代码
class A {
  def showGreeting(
    greeting: String = "Hello",
    name: String,
    year: Int = 2025,
    month: Int,
    day: Int
  ): Unit = {
    println(s"${greeting} ${name}, today is ${year}-${month}-${day}")
  }

  def callerFunction(): Unit = {
    showGreeting(name = "小明", month = 7, day = 29);
  }
}

scalac A.scala 命令进行编译之后,会生成 A.class 文件。用 javap -p A 命令可以查看 A.class 中的简要内容。 结果如下

text 复制代码
Compiled from "A.scala"
public class A {
  public A();
  public void showGreeting(java.lang.String, java.lang.String, int, int, int);
  public java.lang.String showGreeting$default$1();
  public int showGreeting$default$3();
  public void callerFunction();
}

class 文件里,A 类有 5 个函数

  1. 构造函数 A()
  2. showGreeting(String, String, int, int, int) 函数
  3. showGreeting$default$1() 函数
  4. showGreeting$default$3() 函数
  5. callerFunction() 函数

javap -v -p A 命令可以查看 A.class 中的详细内容。 如果自己手动把结果转化为 java 代码,会有些枯燥,可以借助 Visual Studio Code 里的 Decompiled Java Class File 的帮助 ⬇️

可以手动将结果转化为 java 代码,结果如下 ⬇️

java 复制代码
// 以下 java 代码是我在 Visual Studio Code 的帮助下手动转化的,不保证绝对准确,仅供参考

public class A {
    public A() {
        super();
    }
   
    // 为了便于阅读,这个函数的缩进做了些调整
    public void showGreeting(
        final java.lang.String greeting, 
        final java.lang.String name, 
        final int year, 
        final int month, 
        final int day) {
        scala.Predef$.MODULE$.println(
            new StringBuilder(14).
                append(greeting).
                append(" ").
                append(name).
                append(", today is ").
                append(year).append("-").
                append(month).
                append("-").
                append(day).
                toString()
            );
    }

    // 用于为 showGreeting(...) 函数里的第 1 个参数(即 greeting)提供缺省值
    public java.lang.String showGreeting$default$1() {
        return "Hello";
    }

    // 用于为 showGreeting(...) 函数里的第 3 个参数(即 year)提供缺省值
    public int showGreeting$default$3() {
        return 2025;
    }

    // 为了便于阅读,这个函数的缩进做了些调整
    public void callerFunction() {
        this.showGreeting(
            this.showGreeting$default$1(), // 获取 greeting 参数的缺省值
            "小明",
            this.showGreeting$default$3(), // 获取 year 参数的缺省值
            7,
            29
        );
   }
}

调用 callerFunction() 时,主要步骤如下 ⬇️

其他

主要步骤是如何画出来的

我是在 mermaid.live/ 上画出来的,用到的代码如下 ⬇️

text 复制代码
---
config:
  layout: dagre
---
flowchart LR
 subgraph "主要步骤"
 subgraph s1["In _Scala_ source code"]
        A["_**callerFunction()**_ calls _**showGreeting(...)**_ with explicit _**name/month/day**_ parameters"]
  end
 subgraph s2["In _class_ file"]
      X["Step1: _**callerFunction()**_ populates _**greeting**_ parameter with the return value from _**showGreeting$default$1()**_"]
      Y["Step2: _**callerFunction()**_ populates _**year**_ parameter with the return value from _**/showGreeting$default$3()**_"]
      Z["Step3: _**callerFunction()**_ calls _**showGreeting(...)**_ with _5_ explicit parameters"]
  end
    s1 -- 转化为 --> s2
end
相关推荐
还是大剑师兰特2 天前
Scala面试题及详细答案100道(11-20)-- 函数式编程基础
scala·大剑师·scala面试题
华科云商xiao徐8 天前
响应式爬虫系统设计:Scala异步任务编排与弹性容错机制
爬虫·scala
ChipCamp12 天前
Chisel芯片开发入门系列 -- 18. CPU芯片开发和解释8(流水线架构的代码级理解)
开发语言·青少年编程·fpga开发·scala·dsp开发·risc-v·chisel
渣渣盟13 天前
Flink从Kafka读取数据的完整指南
flink·kafka·scala
ChipCamp17 天前
Chisel芯片开发入门系列 -- 14. CPU芯片开发和解释4(Load/Store指令再探)
arm开发·青少年编程·fpga开发·scala·dsp开发·risc-v·chisel
hweiyu0018 天前
Scala实用编程(附电子书资料)
开发语言·后端·scala
hweiyu0019 天前
Scala实现常用排序算法
开发语言·排序算法·scala
hweiyu0019 天前
学习Scala语言的最佳实践有哪些?
开发语言·学习·scala
数据智能老司机25 天前
函数式事件驱动架构——交易系统(可观测性)
架构·scala·响应式设计