RGC 是一门 Python 风格、编译型、内存安全 的系统编程语言。语法上你几乎不用重新学习——def、if、for、and、None 都还在;但它在编译期完成类型检查和所有权检查,由 LLVM 生成原生机器码,性能接近 C / Rust。
这篇教程面向 Python 开发者,从零开始:先跑起第一个程序,再逐个掌握语法、类型、所有权、泛型、模块与标准库,最后用一个成绩管理器小项目把全部知识串起来。所有示例都来自仓库中可编译运行的代码,你可以直接复制运行。
1. 环境准备
1.1 构建编译器
RGC 采用自举(bootstrapping)构建:stage0 是 C++ 编写的一次性种子,之后由 RGC 自身逐级编译出 stage1 → stage2 → stage3,最终编译器完全由 RGC 构建。
先安装依赖:
- LLVM 23(自包含发行包,默认路径
/home/bluemoon/llvm/LLVM-23.1.4-Linux-X64/bin) - CMake ≥ 3.31
- GCC 13.3+ 或 Clang
克隆仓库并构建:
git clone https://github.com/rgc-lang
cd RGLite
cd src
./build.sh
首次构建会自动编译 C++ 引导种子;之后 rack 会管理 rgc1 → rgc2 → rgc3 的逐级自举,并校验 IR 不动点。构建产物在 src/build/rgc3。
1.2 编译并运行第一个程序
cd src
./build/rgc3 ../examples/hello.rg -o /tmp/hello
/tmp/hello
输出:
hello from RGC, x + y = 42
condition: ok
score 95 => excellent
score 70 => pass
score 30 => fail
flag = True
7 // 2 = 3 7 % 2 = 1 2 ** 10 = 1024
rgc3 内嵌 LLVM,运行时只需要系统链接器 gcc,不需要额外安装 llc 或 clang。
2. 第一个程序:Hello World
来看 examples/hello.rg 的完整内容:
def add(a: int, b: int) -> int {
return a + b
}
def classify(score: int) -> str {
if score >= 90 {
return "excellent"
} elif score >= 60 {
return "pass"
} else {
return "fail"
}
}
def main() {
x = 40
y: int = 2
total = add(x, y)
print("hello from RGC, x + y =", total)
if x > 10 and y < 10 {
print("condition: ok")
} else {
print("condition: no")
}
flag = not (x == 0)
print("flag =", flag)
print("7 // 2 =", 7 // 2, " 7 % 2 =", 7 % 2, " 2 ** 10 =", 2 ** 10)
}
即使没有 Python 背景,这段代码也几乎可以无障碍阅读。几个要点:
- 入口函数是
main(),和 Python 脚本一样。 - 变量
x = 40无需mut——RGC 的变量默认可变,符合 Python 习惯。 y: int = 2是显式类型注解;x则由编译器推断为int。- 块结构用大括号
{},不依赖缩进,注释是#。 - 逻辑运算符沿用 Python 风格:
and、or、not。 //(整除)、%(取模)、**(幂)都与 Python 一致。
注意一个与 Python 不同的细节:两个整数相除 / 得到整数(与 C 一致),浮点数参与才会得到浮点结果。例如 7 / 2 结果是 3,而 7.0 / 2 是 3.5。
3. 变量与类型系统
RGC 是静态类型语言:每个表达式在编译期都有确定的类型。但类型推断让你不必到处写注解。
| 类型 | 说明 | 示例 |
|---|---|---|
int |
整数 | 42 |
float |
浮点数 | 3.14 |
bool |
布尔值 | True / False |
str |
字符串 | "hello" |
None |
空值 | None |
def main() {
count = 1 # 推断为 int
name = "RGC" # 推断为 str
ratio: float = 0.5 # 显式注解为 float
ok: bool = True
}
函数签名可以完整标注参数与返回类型,让错误尽早暴露在编译期:
def scale(x: float, factor: int) -> float {
return x * factor
}
4. 函数与控制流
4.1 函数
def greet(name: str) {
print("Hello,", name)
}
返回值类型可以省略;需要返回时用 return。
4.2 if / elif / else
def classify(n: int) -> str {
if n < 0 {
return "negative"
} elif n == 0 {
return "zero"
} else {
return "positive"
}
}
4.3 循环:for / while / break / continue / pass
def main() {
# for 遍历 range
for i in range(5) { # 0 1 2 3 4
print(i)
}
# while + continue + break
i = 0
while i < 6 {
i = i + 1
if i == 2 {
continue
}
if i == 5 {
break
}
print("i =", i)
}
# pass 空语句
n = 0
while n < 3 {
n = n + 1
pass
}
}
range、break、continue、pass 的语义与 Python 一致,只是块结构换成大括号。
5. 类、枚举与模式匹配
RGC 提供完整的代数数据类型(ADT):class 组织数据与方法,enum 描述"要么是 A、要么是 B"的枚举,配合 match 做穷尽的模式匹配。
class Point {
x: int
y: int
def sum(self) -> int {
return self.x + self.y
}
}
enum Shape {
Circle(float)
Rect { w: float, h: float }
}
def area(s: Shape) -> float {
match s {
case Circle(r) => 3.14159 * r * r
case Rect { w, h } => w * h
case _ => 0.0
}
}
def main() {
p = Point()
p.x = 3
p.y = 4
print("p.sum() =", p.sum()) # 7
c = Circle(2.0)
r = Rect(3.0, 4.0)
print("area(circle) =", area(c))
print("area(rect) =", area(r))
}
几个和 Python 不一样的写法:
- 枚举变体用构造函数语法创建:
Circle(2.0)、Rect(3.0, 4.0);没有参数的单位变体写成Pass()。 match的case不需要括号:case Circle(r)直接把负载绑定到变量r。case _是通配分支,保证匹配一定完整。
6. 所有权与借用
这是 RGC 内存安全的核心,也是和 Python 最大的不同。每个值有唯一的拥有者,离开作用域即被释放;通过借用安全地共享访问。全程没有 GC,零运行时开销。
6.1 移动(move)
自定义类型(class / enum)默认是 move 语义。赋值后原变量不再可用:
class Point {
x: int
def sum(self) -> int {
return self.x
}
}
def main() {
a = Point()
a.x = 5
b = a # 所有权从 a 移动到 b
print("b.x =", b.x) # 5
# print(a) # 编译错误:a 已被 move
}
被移动的变量在重新赋值后可以恢复可用:
d = Point()
d.x = 7
e = d # move d -> e
d = Point() # 重新赋值,d 恢复可用
d.x = 8
6.2 只读借用 @ 与可变借用 @var
不想转移所有权、只想读,用 @ 借用。以自定义类型为例:
class Counter {
value: int
}
def read(c: @Counter) -> int {
return c.value
}
def main() {
x = Counter()
x.value = 10
r1 = @x # 只读借用
r2 = @x # 多个 @ 可以并存
print("read(r1) =", read(r1)) # 10
print("read(r2) =", read(r2)) # 10
print("x.value =", x.value) # x 仍然可用
}
想修改,用 @var 可变借用(独占访问):
def push_zero(lst: @var List[int]) {
lst.push(0)
}
多个 @ 只读借用可以并存;@var 与任何其他借用互斥——这一切都在编译期检查,保证没有 use-after-move、悬垂引用和数据竞争。
6.3 方法调用自动借用
调用 self 方法时,方法按借用语义自动处理,不需要手动写 @。可变方法自动使用可变借用:
class Counter {
value: int
def inc(self) {
self.value = self.value + 1
}
}
def main() {
z = Counter()
z.value = 30
z.inc() # self 自动可变借用
print(z.value) # 31,z 仍可用
}
7. 泛型与接口
7.1 泛型函数
def identity[T](x: T) -> T {
return x
}
def pair_sum[T](a: T, b: T) -> T {
return a + b
}
def main() {
print(identity(42)) # 42
print(identity(3.14)) # 3.14
print(pair_sum(2, 3)) # 5
print(pair_sum(1.5, 2.5)) # 4.0
}
7.2 泛型类
class Box[T] {
value: T
def get(self) -> T {
return self.value
}
}
def main() {
b = Box[int]()
b.value = 42
print(b.get()) # 42
f = Box[float]()
f.value = 3.14
print(f.get()) # 3.14
}
7.3 接口与边界约束
接口定义行为契约,类通过 class T : Interface 实现:
interface Show {
def show(self) -> str
}
class Point : Show {
x: int
y: int
def show(self) -> str {
return "Point"
}
}
class Line : Show {
a: int
b: int
def show(self) -> str {
return "Line"
}
}
# T 受 Show 约束,函数体内可直接调用接口方法
def describe[T: Show](x: T) -> str {
return x.show()
}
def main() {
p = Point()
p.x = 1
p.y = 2
print(describe(p)) # Point
l = Line()
l.a = 3
l.b = 4
print(describe(l)) # Line
}
泛型通过单态化编译:每个具体类型生成专用代码,没有虚表、没有装箱,性能和手写专用实现一致。
8. 模块系统
用 import 引入模块,模块内部通过 public 控制可见性。未加 public 的项只在模块内部可见。
geometry.rg:
public class Point {
x: int
y: int
def sum(self) -> int {
return self.x + self.y
}
}
# 私有函数:仅模块内部可见
def double(v: int) -> int {
return v * 2
}
public def make_point(x: int, y: int) -> Point {
p = Point()
p.x = x
p.y = y
return p
}
public def norm_sq(p: Point) -> int {
return double(p.x * p.x + p.y * p.y)
}
main.rg:
import geometry
def main() {
p = make_point(3, 4)
print("point sum =", p.sum()) # 7
print("norm_sq =", norm_sq(p)) # 50
}
注意 norm_sq 内部调用了私有函数 double,但对外只暴露 public 项——内部实现细节被安全地封装在模块边界内。
9. 标准库初探
标准库目前提供内建核心类型与方法:to_string、字符串方法、List[T]、Maybe[T]、Result[T, E]。
9.1 字符串
def main() {
msg = "Hello, " + "RGC"
print(msg.len()) # 10
print(msg.contains("lo,")) # True
print(msg.startswith("Hello")) # True
print(msg.endswith("RGC")) # True
print("hello world".slice(0, 5)) # hello
print("12345".to_int().unwrap()) # 12345
}
9.2 List
def main() {
xs = List[int]()
xs.push(1)
xs.push(2)
xs.push(3)
print(xs.len()) # 3
print(xs.get(0)) # 1
xs.set(1, 20)
print(xs.get(1)) # 20
print(xs.contains(3)) # True
print(xs.pop()) # 3
total = 0
for x in xs {
total = total + x
}
print(total) # 21
}
9.3 Maybe 与 Result
RGC 用 Result[T, Err] 表达可恢复错误:不抛异常、不静默失败。解析字符串可能失败时,签名里就写着"可能失败":
def main() {
ok = Result[int, str].Ok(7)
err = Result[int, str].Err("boom")
print(ok.is_ok()) # True
print(err.is_err()) # True
# match 推荐用法:错误分支显式处理
match err {
case Ok(v) => print("unexpected:", v)
case Err(msg) => print("error is:", msg)
}
}
配合字符串的 to_int():
r = "12345".to_int()
match r {
case Ok(v) => print("value =", v) # value = 12345
case Err(msg) => print("err:", msg)
}
bad = "abc".to_int()
match bad {
case Ok(v) => print("unexpected:", v)
case Err(msg) => print("to_int error:", msg) # invalid integer literal
}
10. 实战:成绩管理器
现在把上面的知识串起来,写一个小程序:录入三名学生成绩,输出每个人的等级、及格人数和平均分。这会用到类、接口、枚举、模式匹配、List、所有权与借用、泛型边界。
interface Show {
def show(self) -> str
}
class Student : Show {
name: str
score: int
def show(self) -> str {
return self.name + ": " + to_string(self.score)
}
def is_pass(self) -> bool {
return self.score >= 60
}
}
enum Grade {
Excellent
Pass
Fail
}
def grade_of(score: int) -> Grade {
if score >= 90 {
return Excellent()
} elif score >= 60 {
return Pass()
} else {
return Fail()
}
}
def grade_name(g: Grade) -> str {
match g {
case Excellent => "优秀"
case Pass => "及格"
case Fail => "不及格"
case _ => "?"
}
}
def total(students: @List[Student]) -> int {
sum = 0
for s in students {
sum = sum + s.score
}
return sum
}
def count_pass(students: @List[Student]) -> int {
n = 0
for s in students {
if s.is_pass() {
n = n + 1
}
}
return n
}
def main() {
students = List[Student]()
s = Student()
s.name = "Alice"
s.score = 92
students.push(s) # push 移动所有权,s 可重新赋值
s = Student()
s.name = "Bob"
s.score = 74
students.push(s)
s = Student()
s.name = "Carol"
s.score = 55
students.push(s)
for st in students {
print(st.show(), "=>", grade_name(grade_of(st.score)))
}
print("及格人数 =", count_pass(@students))
print("平均分 =", total(@students) / students.len())
}
运行输出:
Alice: 92 => 优秀
Bob: 74 => 及格
Carol: 55 => 不及格
及格人数 = 2
平均分 = 73
几个值得回味的点:
students.push(s)把s移动进列表;之后给s重新赋值一个新Student(),符合所有权模型。for st in students按借用迭代,循环结束后students仍然可用。count_pass(@students)和total(@students)用@只读借用传入列表,调用后students不受影响。grade_name用match把枚举变体映射成中文标签,编译期保证分支完整。class Student : Show实现了接口,show()在for循环里被多态调用(单态化,无虚表开销)。
11. 下一步
至此你已经掌握了 RGC 的核心:从语法、类型,到所有权、泛型、模块和标准库。继续深入:
RGC 以 Apache 2.0 协议开源。欢迎在 GitHub 提 Issue、贡献代码;也欢迎安装 VSCode 插件,获得语法高亮与补全支持。祝你写得开心!