在学习 C 语言的过程中,很多 Java/Kotlin 背景的开发者都会对结构体中出现的“函数指针”感到陌生。特别是当看到如下代码时:
struct Animal {
void (*speak)(void);
};
void dogSpeak() {
printf("Woof!\n");
}
int main() {
struct Animal dog;
dog.speak = dogSpeak;
dog.speak();
return 0;
}
这段代码中,结构体 Animal
中的 speak
并不是一个普通变量,而是一个“函数指针”。它的作用是:指向一个函数,然后在合适的时机调用它。这其实与我们在 Kotlin 中使用高阶函数的目的如出一辙。
一、C 中结构体里的函数指针
函数指针的语法可能略显复杂,但本质很简单:
void (*speak)(void)
表示一个函数指针,它指向一个没有参数、返回值为void
的函数。- 给它赋值时,只需要提供函数名(不加括号)。
- 调用时使用
结构体变量.函数指针()
的方式执行。
函数指针的最大好处是:可以将函数“作为变量”赋值和传递,从而实现类似回调、策略模式等逻辑。
二、Kotlin 中的高阶函数
Kotlin 提供了原生的高阶函数支持,比如下面这个例子:
fun runTwice(block: () -> Unit) {
block()
block()
}
fun main() {
runTwice { println("Hello") }
}
这里,block: () -> Unit
就是一个“函数类型的参数”,你可以将任何匹配这个签名的 lambda 或函数传入它。
Kotlin 的高阶函数与 C 的函数指针的本质是一样的:将函数作为“值”进行传递、赋值和调用。
三、类比与思考
概念 | C 语言 | Kotlin |
---|---|---|
函数作为变量 | 函数指针 | 高阶函数(函数类型) |
放入结构/对象中 | 结构体中的函数指针成员 | 类/对象中的函数属性 |
调用方式 | 对象.函数指针() |
对象.函数() |
使用目的 | 实现回调、策略、接口模拟 | 回调、DSL、扩展性逻辑 |
🎯 本质对齐:
✅ C 的函数指针 和 Kotlin 的高阶函数,本质都是“把函数当变量传来传去”,用来实现回调、事件处理、状态切换等逻辑的解耦。
📌 下面我们一一对比一下:
✅ 1. 回调机制 Callback
🧠 C 的函数指针实现回调:
void onDataReceived(void (*callback)(int)) {
int data = 42;
callback(data);
}
void printData(int x) {
printf("Received: %d\n", x);
}
int main() {
onDataReceived(printData);
}
🧠 Kotlin 的高阶函数实现回调:
fun onDataReceived(callback: (Int) -> Unit) {
val data = 42
callback(data)
}
fun main() {
onDataReceived { println("Received: $it") }
}
📌 一模一样的使用场景,只是 Kotlin 更安全、更语义清晰。
✅ 2. 线程回调 / 异步通知
🧠 C 中常用于线程启动函数传递:
void* thread_func(void* arg) {
printf("Thread running...\n");
return NULL;
}
pthread_t t;
pthread_create(&t, NULL, thread_func, NULL);
🧠 Kotlin 用 Thread
+ Lambda 更优雅:
Thread {
println("Thread running...")
}.start()
✔️ Kotlin 的 Lambda 本质就是回调函数传给线程入口。
✅ 3. 状态机中的动作抽象(状态 -> 函数映射)
🧠 C 用函数指针数组管理状态:
void stateA() { printf("A\n"); }
void stateB() { printf("B\n"); }
void (*states[2])() = {stateA, stateB};
int main() {
int current = 0;
states[current](); // 调用状态A
}
🧠 Kotlin 用 Map 或函数引用也一样:
val stateMap: Map<String, () -> Unit> = mapOf(
"A" to { println("A") },
"B" to { println("B") }
)
fun main() {
val current = "A"
stateMap[current]?.invoke()
}
✔️ Kotlin 的函数也是变量,完全可以当成状态管理工具。
四、小结
- C 的函数指针虽然语法复杂,但功能强大,可以动态指定调用的函数。
- Kotlin 的高阶函数使用更灵活简洁,是现代语言的核心能力之一。
- 它们都体现了 “把函数当变量” 的思想,使得“回调”“策略”“事件响应”等模式得以实现。
所以,函数指针和高阶函数虽然语言不同,但思想一致、目标相同——赋予函数灵活的表达力。