Go语言有25个关键字,Solod只用了9个。这不是精简,是截肢——但截肢后居然能跑。

Solod(简称So)是个刚开源的项目,做了一件听起来很荒唐的事:把Go语言砍掉70%的特性,只留一个严格子集,然后完整翻译成C代码。零运行时、手动内存管理、源码级互操作——这三个词放在一起,像是把Rust和C的执念强行塞进Go的语法壳里。

作者没有解释为什么叫"Solod",但社区有人猜是"So long, Go runtime"的缩写。不管真假,这个名字确实贴切。

从"Hello World"到裸机:一次翻译的解剖

看一段最简单的Go代码怎么被肢解。你写:

```go package main type Person struct { Name string Age int Nums [3]int } func (p *Person) Sleep() int { p.Age += 1 return p.Age } func main() { p := Person{Name: "Alice", Age: 30} p.Sleep() println(p.Name, "is now", p.Age, "years old.") } ```

Solod吐出两份文件。头文件`main.h`里,Go的`string`变成`so_String`结构体,方法变成裸函数指针:

```c typedef struct main_Person { so_String Name; so_int Age; so_int Nums[3]; } main_Person; so_int main_Person_Sleep(void* self); ```

实现文件`main.c`更直白。Go的隐式指针解引用没了,你得自己写`p->Age += 1`。`println`变成宏展开的`so_println`,字符串格式化用`%.*s`这种C标准写法——Go程序员在这里会愣一下,C程序员会觉得回家了一样

整个翻译过程没有垃圾回收的隐藏代码,没有goroutine调度器的初始化,没有反射的元数据表。生成的C代码就是你写的逻辑,一字一句对应。

被砍掉的和留下的:一份残酷的取舍清单

被砍掉的和留下的:一份残酷的取舍清单

Solod的支持列表读起来像Go语言的悼词。留着的是:结构体、方法、接口、切片、多返回值、defer。这些够写大部分业务逻辑。

被砍掉的是:通道(channel)、goroutine、闭包、泛型。还有反射、CGO、panic/recover的完整机制。作者的原话是"To keep things simple"——但谁都知道,砍掉goroutine等于抽掉了Go的脊椎

这个取舍暴露了一个尴尬的事实:Go的并发原语和运行时深度绑定,想要零运行时,就得连根拔起。Solod的选择是,宁可不要并发,也要可预测的内存布局。

留下的`defer`是个例外。C语言没有finally块,资源泄漏是老大难。Solod把`defer`翻译成C的`goto`链——没错,就是Dijkstra骂了六十年的那个`goto`。但在这里,它成了自动生成的清理代码的跳转到点。一种语法糖,两种截然不同的实现哲学

谁需要这个怪胎?嵌入式和 FFI 的两难

谁需要这个怪胎?嵌入式和 FFI 的两难

Solod的README很诚实:目标是"systems programming in C, but with Go's syntax"。不是取代Go,是给那群必须用C、但恨透了C的人一个逃生通道。

具体场景有三类。第一类是嵌入式开发,8KB内存容不下Go的运行时,但手写C容易出错。Solod生成的C代码没有隐藏分配,栈帧大小编译期确定,适合静态分析工具。

第二类是C库的FFI绑定。用Go写绑定层,翻译后直接link进C项目,不需要cgo的指针传递规则。一个实际例子:某数据库团队用Solod重写了客户端驱动,延迟从cgo的微秒级降到纳秒级——因为消除了Go和C之间的线程切换开销。

第三类更微妙:教学。Go的语法干净,适合教编程;但学生最终要理解内存和指针。Solod是个中间态——你先写Go风格的代码,再看它翻译成什么样的C,逐步揭开抽象层。

但限制也很硬。没有泛型,你得手写`IntSlice`和`StringSlice`。没有闭包,回调函数必须传显式的`void* userdata`。没有goroutine,并发得自己调`pthread`——这时候你会发现,Solod生成的C代码和手写C一样难搞

工具链的野心:不只是翻译器

工具链的野心:不只是翻译器

Solod的命令行设计很Go化。`so translate`输出C代码,`so build`一步到位编译,`so run`像脚本一样执行。它认Go module,不认单文件——这个选择暴露了作者的预期:你是来正经做项目的,不是写leetcode。

标准库的分层更有意思。高层包模仿Go的`math`、`strings`;低层包直接wrap libc。一个细节:`so/math.Sqrt`在x86-64上可能直接生成`sqrtsd`指令,而不是调用C的`sqrt`——作者在做跨平台的内联优化,但文档里没提,得看生成的汇编

在线Playground是个聪明的传播工具。你可以写Go代码,实时看C输出,不用装任何东西。这对犹豫要不要引入的团队很重要:先验证你的代码能不能翻译,再决定迁移成本。

但"rough around the edges"的警告不是客气。GitHub issue里有人报告:嵌套接口类型会生成错误的vtable,某些切片操作在-O2优化下会越界。项目才开源几周,这些坑需要踩。

社区的反应分裂得很有意思。Hacker News上,C程序员说"终于有人做了",Go程序员说"这失去了Go的灵魂"。一个高赞评论是:"这就像把Python翻译成C——语法还在,但写代码的快感没了。"

Solod的作者没有回应这些争论。 roadmap里列着泛型的实验性支持、更好的错误信息、Windows移植。但goroutine不在列表上——那个"So"里的"long",可能是永别。

如果让你选:用Solod写能翻译成C的Go代码,还是直接学Rust?