C 语言结构体中的函数指针与 Kotlin 高阶函数的对比

发布于:2025-04-20 ⋅ 阅读:(23) ⋅ 点赞:(0)

在学习 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 的高阶函数使用更灵活简洁,是现代语言的核心能力之一。
  • 它们都体现了 “把函数当变量” 的思想,使得“回调”“策略”“事件响应”等模式得以实现。

所以,函数指针和高阶函数虽然语言不同,但思想一致、目标相同——赋予函数灵活的表达力。


网站公告

今日签到

点亮在社区的每一天
去签到