0%

scala函数

Scala 函数:灵活高效的代码块封装

在 Scala 中,函数是代码复用和逻辑封装的核心单位,其灵活性远超 Java 中的方法 —— 不仅可以独立定义,还能像变量一样赋值、传递,甚至作为参数或返回值。本文将深入解析 Scala 函数的定义、参数特性及使用技巧。

函数与方法的关系

Scala 中 “函数”(Function)和 “方法”(Method)概念相近,但存在细微区别:

  • 方法:定义在类、对象或特质中的函数,依赖于宿主结构。
  • 函数:可独立存在的代码块,本质是 FunctionN 特质的实例(如 Function2 对应两个参数的函数)。

日常使用中,两者常被混用,因为 Scala 会自动在方法和函数间转换(通过 “eta 展开”:方法名 _ 将方法转为函数)。

函数的基本定义

Scala 函数通过 def 关键字声明,语法灵活,支持多种返回值形式。

基本语法

1
2
3
4
def 函数名([参数名: 参数类型], ...)[[: 返回值类型] =] {
函数体
[return 返回值]
}

三种返回值形式

1. 显式指定返回值类型

通过 : 返回值类型 = 明确声明返回值类型,可使用 return 关键字。

1
2
3
4
5
6
7
// 定义加法函数,显式指定返回值为Int
def add(a: Int, b: Int): Int = {
return a + b // return可省略(Scala推荐省略)
}

// 简化写法:函数体为单行表达式时可省略花括号
def add(a: Int, b: Int): Int = a + b
类型推导(省略返回值类型)

通过 = 省略返回值类型,编译器会自动推导。注意:此时不能用 return,否则推导失败

1
2
3
4
5
// 编译器自动推导返回值为Int
def add1(a: Int, b: Int) = a + b

// 推导为String
def greet(name: String) = s"Hello, $name"
无返回值(Unit 类型)

两种写法:省略 = 或显式声明返回值为 Unit(类似 Java 的 void)。

1
2
3
4
5
6
7
8
9
// 写法1:省略=,默认返回Unit
def printSum(a: Int, b: Int) {
println(s"Sum: ${a + b}")
}

// 写法2:显式声明Unit
def printSum(a: Int, b: Int): Unit = {
println(s"Sum: ${a + b}")
}

注意:无返回值函数中,return 无效(即使写了也不会返回值)。

函数的调用与赋值

函数调用

  • 有参数的函数:直接传递参数,如 add(1, 2)
  • 无参数的函数:可省略括号,如 def hello() = println("hi") 可调用为 hello
1
2
3
def hello(): Unit = println("Hello")
hello() // 合法
hello // 合法(无参函数可省略括号)

函数赋值给变量

通过 函数名 _ 将函数转换为函数值(类似 Java 的 lambda 引用),赋值给变量。

1
2
3
4
5
def add(a: Int, b: Int): Int = a + b

// 将函数add赋值给变量f(_表示不立即执行)
val f = add _
println(f(2, 3)) // 输出:5(通过变量调用函数)

函数参数的高级特性

Scala 函数参数支持默认值、带名参数、可变参数等特性,极大提升灵活性。

默认值参数

声明参数时指定默认值,调用时可省略该参数(使用默认值)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 定义带默认值的连接函数
def connect(
host: String = "localhost",
port: Int = 3306,
user: String = "root",
password: String = "root"
): Unit = {
println(s"host:$host, port:$port, user:$user, password:$password")
}

// 调用示例
connect() // 全用默认值:host:localhost, port:3306, ...
connect("127.0.0.1", 8080) // 从左到右覆盖:host:127.0.0.1, port:8080, ...
connect(password = "123456") // 带名参数:只覆盖password

优势:减少重载函数的定义,灵活适配不同调用场景。

带名参数

调用时通过 参数名 = 值 指定参数,无需严格按顺序传递。

1
2
3
// 无需按顺序,直接指定参数名
connect(user = "admin", host = "192.168.1.1")
// 输出:host:192.168.1.1, port:3306, user:admin, password:root

可变参数

通过 参数名: 类型* 声明可变参数(0 到多个值),必须放在参数列表最后。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 定义可变参数函数(计算多个整数的和)
def sum(numbers: Int*): Int = {
var total = 0
for (n <- numbers) total += n
total
}

// 调用示例
sum(1, 2, 3) // 输出:6
sum() // 输出:0(空参数)

// 传递数组给可变参数(需加_*)
val nums = Array(1, 2, 3, 4)
sum(nums: _*) // 输出:10

参数的不可变性

Scala 函数的参数默认是 val 类型,不允许在函数体内修改(避免副作用)。

1
2
3
4
def increment(a: Int): Int = {
// a += 1 // 编译错误:参数a是val,不可修改
a + 1
}

函数与方法的核心区别

特性 函数(Function) 方法(Method)
定义位置 可独立定义,或在方法 / 函数内部 必须定义在类、对象或特质中
本质 FunctionN 特质的实例(对象) 类的成员,依赖宿主
赋值给变量 直接赋值(如 val f = (a: Int) => a + 1 需通过 _ 转换(如 val f = obj.method _
参数括号省略 无参数函数调用可省略括号 无参数方法定义时带括号,调用可省略

最佳实践

  1. 优先省略 return:Scala 函数默认返回最后一行表达式的值,省略 return 使代码更简洁。
  2. 使用类型推导:简单函数可省略返回值类型,由编译器自动推导。
  3. 合理使用默认参数:减少重载,简化多参数函数的调用。
  4. 避免修改参数:尊重参数的 val 特性,通过返回新值实现逻辑(函数式风格)。

欢迎关注我的其它发布渠道