Golang、Rust、Java 基本语法对照
Golang、Rust、Java 基本语法对照
基于 Go 1.22+、Rust 1.7x+、Java 21+ 的现代版本编写。
面向需要在三种语言间切换、或从一门语言迁移到另一门的开发者。
目录
- 语言概览与设计理念
- 程序结构与入口
- 基本数据类型
- 变量、常量与可变性
- 运算符与表达式
- 控制流
- 函数与方法
- 复合类型:数组、切片、集合
- 结构体、类与面向对象
- 接口、Trait 与多态
- 枚举与代数数据类型
- 错误处理
- 泛型
- 包、模块与可见性
- 内存管理与指针
- 并发编程
- 字符串处理
- 注解、属性与元编程
- 测试
- 综合对比速查表
1. 语言概览与设计理念
| 维度 | Go | Rust | Java |
|---|---|---|---|
| 编译模型 | 编译为原生机器码 | 编译为原生机器码 | 编译为 JVM 字节码 |
| 运行时 | 极小运行时 + GC | 无 GC,所有权系统 | JVM + GC |
| 类型系统 | 静态、结构化、名义类型 | 静态、强类型、名义 + 结构等价 | 静态、名义类型、单继承 |
| 面向对象 | 组合 + 接口(无类继承) | 组合 + Trait(无类继承) | 类继承 + 接口实现 |
| 空值 | nil(指针/引用/切片/map/channel/interface) |
Option<T>(无 null) |
引用类型可为 null |
| 异常 | 无传统异常,返回 error |
Result<T, E> + panic! |
try/catch/throw |
| 泛型 | 1.18+ 支持(类型参数) | 完整泛型 + 关联类型 | 完整泛型 + 通配符 |
| 并发模型 | goroutine + channel(CSP) | thread + async/await + channel | Thread + Executor + CompletableFuture |
| 包管理 | Go Modules | Cargo | Maven / Gradle |
| 主要设计目标 | 简单、高并发、工程效率 | 安全、性能、零成本抽象 | 跨平台、生态成熟、企业级 |
共同点:
- 均为静态类型语言,编译期做大量类型检查。
- 均支持泛型(Go 相对较晚引入)。
- 均强调接口/Trait 式多态,而非仅靠继承。
- 均有成熟的工具链与包/模块系统。
核心差异:
- Go:语法极简,GC 省心,goroutine 开箱即用,牺牲部分类型表达力换开发速度。
- Rust:编译期通过所有权/借用检查保证内存安全,无 GC,学习曲线陡,性能与可控性极强。
- Java:成熟 OOP 范式,JVM 生态庞大,运行时反射/动态特性丰富,启动与内存开销相对更大。
2. 程序结构与入口
2.1 Hello World
Go:
package main
import "fmt"
func main() {
fmt.Println("Hello, Go!")
}
Rust:
fn main() {
println!("Hello, Rust!");
}
Java:
public class Main {
public static void main(String[] args) {
System.out.println("Hello, Java!");
}
}
2.2 对比要点
| 特性 | Go | Rust | Java |
|---|---|---|---|
| 入口函数 | func main() |
fn main() |
public static void main(String[] args) |
| 文件与类型关系 | 一个文件可含多个类型,但 main 包需有 main() |
可有多个函数/类型,main 在 main.rs 或 lib.rs |
公共类名通常与文件名一致 |
| 语句结尾 | 不需要分号(多数情况) | 表达式无分号,语句有分号 | 需要分号 |
| 包声明 | package main |
mod / crate 体系 |
package com.example; |
相似性: 三者都是编译型语言,程序从 main 入口启动。
差异性:
- Java 强制类包裹一切,连
main也必须在类中。 - Go/Rust 支持顶层函数,无需类包装。
- Rust 的
println!是宏(!标识),不是普通函数。
3. 基本数据类型
3.1 整数与浮点
| 类型 | Go | Rust | Java |
|---|---|---|---|
| 有符号整数 | int8 int16 int32 int64 int |
i8 i16 i32 i64 i128 isize |
byte short int long |
| 无符号整数 | uint8 uint16 uint32 uint64 uint |
u8 u16 u32 u64 u128 usize |
无(char 是 16 位 Unicode) |
| 浮点 | float32 float64 |
f32 f64 |
float double |
| 布尔 | bool |
bool |
boolean |
| 字符 | rune(int32,Unicode 码点) |
char(4 字节 Unicode 标量) |
char(2 字节 UTF-16 单元) |
| 字节 | byte(uint8 别名) |
u8 |
byte(有符号 byte) |
Go:
var a int = 42
b := int64(100)
var f float64 = 3.14
Rust:
let a: i32 = 42;
let b = 100i64;
let f: f64 = 3.14;
Java:
int a = 42;
long b = 100L;
double f = 3.14;
3.2 类型转换
| 语言 | 方式 | 特点 |
|---|---|---|
| Go | T(v) 显式转换 |
不做隐式数值转换 |
| Rust | v as T 或 T::from(v) / TryFrom |
无隐式转换,as 可能截断 |
| Java | 隐式拓宽 + 显式强转 (T)v |
基本类型与包装类型自动装箱 |
Go:
var i int = 42
var f float64 = float64(i)
Rust:
let i: i32 = 42;
let f = i as f64;
let s = i.to_string();
Java:
int i = 42;
double f = i; // 隐式拓宽
int j = (int) f; // 显式窄化
Integer boxed = i; // 自动装箱
3.3 字符串与文本
| 特性 | Go | Rust | Java |
|---|---|---|---|
| 字符串类型 | string(不可变 UTF-8) |
String(堆分配 UTF-8)/ &str(切片) |
String(可变)/ 字面量 String |
| 字符字面量 | '中' 非法,用 "中" |
'a'、'中' |
'a'、'中' |
| 多行字符串 | 反引号 `...` |
"""...""" 或 r#"..."# |
"""..."""(15+) |
| 默认编码 | UTF-8 | UTF-8 | UTF-16(内部) |
4. 变量、常量与可变性
4.1 声明语法
Go:
var x int = 10 // 完整声明
var y = 20 // 类型推断
z := 30 // 短变量声明(函数内)
const Pi = 3.14159
const (
StatusOK = 200
StatusNotFound = 404
)
Rust:
let x: i32 = 10; // 默认不可变
let mut y = 20; // 可变
const PI: f64 = 3.14159;
static GLOBAL: i32 = 0;
Java:
int x = 10;
final double PI = 3.14159;
final int STATUS_OK = 200; // 习惯全大写
4.2 可变性对比
| 特性 | Go | Rust | Java |
|---|---|---|---|
| 默认可变性 | 默认可变 | 默认不可变 | 默认可变 |
| 声明可变 | 无需关键字 | let mut |
无需关键字 |
| 常量 | const(编译期) |
const / static |
final(运行时常量) |
| 未使用变量 | 编译错误 | 编译警告(可用 _ 忽略) |
编译警告 |
| 多重赋值 | a, b := 1, 2 |
let (a, b) = (1, 2) |
不支持(可用数组/record) |
| 遮蔽(shadow) | := 可重新声明 |
let 可遮蔽 |
同作用域不可重复声明 |
关键差异:
- Rust 是唯一默认不可变的语言,鼓励显式
mut。 - Go 的
:=可在内层作用域遮蔽外层变量。 - Java 的
final只限制引用/变量重新赋值,不保证对象内部不可变。
4.3 零值 / 默认值
| 语言 | 机制 |
|---|---|
| Go | 未初始化变量有零值:0、""、nil、false |
| Rust | 必须初始化;或用 Default::default() |
| Java | 成员变量有默认值;局部变量必须显式初始化 |
5. 运算符与表达式
5.1 算术与比较
三者均支持:+ - * / %、比较 == != < > <= >=、逻辑 && || !。
| 运算符 | Go | Rust | Java |
|---|---|---|---|
| 整数除法 | 截断 | 截断 | 截断 |
| 自增自减 | 无 ++ 作为表达式的一部分较特殊 |
无 ++/-- |
++ -- |
| 三元运算 | 无(用 if-else) |
无(用 if 表达式) |
cond ? a : b |
| 空合并 | 无原生(用 if err != nil) |
无(用 Option) |
无(用 Optional.orElse) |
| 范围 | 无内置(用 for i := 0; i < n; i++) |
1..5 1..=5 |
IntStream.range() |
Rust if 表达式:
let max = if a > b { a } else { b };
Java 三元:
int max = a > b ? a : b;
5.2 位运算
三者均支持:& | ^ << >>(Rust/Go 还有 >>> 无符号右移)。
5.3 地址与解引用
| 语言 | 取地址 | 解引用 |
|---|---|---|
| Go | &x |
*p |
| Rust | &x / &mut x |
*p |
| Java | 无显式取地址(对象均为引用) | 无指针运算 |
6. 控制流
6.1 if / else
Go:
if x > 0 {
fmt.Println("positive")
} else if x < 0 {
fmt.Println("negative")
} else {
fmt.Println("zero")
}
// if 可带初始化语句
if err := doSomething(); err != nil {
return err
}
Rust:
if x > 0 {
println!("positive");
} else if x < 0 {
println!("negative");
} else {
println!("zero");
}
// if 是表达式
let desc = if x > 0 { "positive" } else { "non-positive" };
Java:
if (x > 0) {
System.out.println("positive");
} else if (x < 0) {
System.out.println("negative");
} else {
System.out.println("zero");
}
6.2 switch / match
| 特性 | Go | Rust | Java |
|---|---|---|---|
| 关键字 | switch |
match |
switch |
| 默认穿透 | 自动 break(1.1+) | 不穿透 | 传统穿透;-> 不穿透 |
| 类型匹配 | switch v := x.(type) |
强大模式匹配 | switch 模式(21+) |
| 穷尽检查 | 无 | 必须覆盖所有分支 | 枚举 switch 需 default 或穷尽 |
| 返回值 | 无(Go 1.18 前) | 是表达式 | switch 表达式(14+) |
Go:
switch day {
case "Mon", "Tue":
fmt.Println("weekday")
case "Sat", "Sun":
fmt.Println("weekend")
default:
fmt.Println("unknown")
}
switch {
case x > 0:
fmt.Println("positive")
case x < 0:
fmt.Println("negative")
}
Rust:
match day {
"Mon" | "Tue" | "Wed" | "Thu" | "Fri" => println!("weekday"),
"Sat" | "Sun" => println!("weekend"),
_ => println!("unknown"),
}
match value {
Some(n) if n > 0 => println!("positive {n}"),
Some(_) => println!("non-positive"),
None => println!("none"),
}
Java:
switch (day) {
case "Mon", "Tue", "Wed", "Thu", "Fri" -> System.out.println("weekday");
case "Sat", "Sun" -> System.out.println("weekend");
default -> System.out.println("unknown");
}
// Java 21 模式匹配
switch (obj) {
case Integer i -> System.out.println("int: " + i);
case String s -> System.out.println("str: " + s);
case null -> System.out.println("null");
default -> System.out.println("other");
}
6.3 循环
Go — 只有 for:
// 经典 for
for i := 0; i < 10; i++ {
fmt.Println(i)
}
// while 风格
for x > 0 {
x--
}
// 无限循环
for {
break
}
// range 遍历
for i, v := range slice {
fmt.Println(i, v)
}
for k, v := range map {
fmt.Println(k, v)
}
Rust:
// loop + break/continue
let mut i = 0;
loop {
if i >= 10 { break; }
println!("{i}");
i += 1;
}
// while
while x > 0 { x -= 1; }
// for 迭代器
for i in 0..10 {
println!("{i}");
}
for (i, v) in vec.iter().enumerate() {
println!("{i} {v}");
}
Java:
// 经典 for
for (int i = 0; i < 10; i++) {
System.out.println(i);
}
// 增强 for
for (String s : list) {
System.out.println(s);
}
// while / do-while
while (x > 0) { x--; }
do { x--; } while (x > 0);
// Stream(函数式)
IntStream.range(0, 10).forEach(System.out::println);
| 循环 | Go | Rust | Java |
|---|---|---|---|
| while | for cond {} |
while cond {} |
while (cond) {} |
| 无限循环 | for {} |
loop {} |
while (true) {} |
| 遍历集合 | range |
for x in iter |
增强 for / Stream |
| 带标签 break | break label |
'label: loop + break 'label |
break label |
7. 函数与方法
7.1 函数定义
Go:
func add(a, b int) int {
return a + b
}
// 多返回值(Go 特色)
func divide(a, b float64) (float64, error) {
if b == 0 {
return 0, errors.New("division by zero")
}
return a / b, nil
}
// 命名返回值
func split(sum int) (x, y int) {
x = sum * 4 / 9
y = sum - x
return // 裸返回
}
Rust:
fn add(a: i32, b: i32) -> i32 {
a + b // 无分号 = 返回值
}
// 多返回值用元组
fn divide(a: f64, b: f64) -> Result<f64, String> {
if b == 0.0 {
Err("division by zero".into())
} else {
Ok(a / b)
}
}
Java:
public static int add(int a, int b) {
return a + b;
}
// 无原生多返回值,用对象/数组/record
public record Pair<A, B>(A first, B second) {}
public static Pair<Double, String> divide(double a, double b) {
if (b == 0) return new Pair<>(0.0, "division by zero");
return new Pair<>(a / b, null);
}
7.2 方法(接收者)
Go — 接收者函数:
type Rectangle struct {
Width, Height float64
}
// 值接收者
func (r Rectangle) Area() float64 {
return r.Width * r.Height
}
// 指针接收者(可修改)
func (r *Rectangle) Scale(factor float64) {
r.Width *= factor
r.Height *= factor
}
Rust — impl 块:
struct Rectangle {
width: f64,
height: f64,
}
impl Rectangle {
fn area(&self) -> f64 {
self.width * self.height
}
fn scale(&mut self, factor: f64) {
self.width *= factor;
self.height *= factor;
}
}
Java — 类方法:
public class Rectangle {
private double width, height;
public double area() {
return width * height;
}
public void scale(double factor) {
width *= factor;
height *= factor;
}
}
7.3 函数特性对比
| 特性 | Go | Rust | Java |
|---|---|---|---|
| 多返回值 | ✅ 原生支持 | ✅ 元组 / Result | ❌ 需包装 |
| 默认参数 | ❌ 用函数重载或选项模式 | ❌ 用 Builder / 宏 | ❌(可用重载) |
| 命名参数 | ❌ | ❌ | ❌ |
| 可变参数 | func f(nums ...int) |
fn f(nums: &[i32]) 或宏 |
void f(int... nums) |
| 函数是一等公民 | ✅ | ✅ | ✅(Lambda,8+) |
| 闭包 | ✅(匿名函数) | ✅ 强大闭包 | ✅ Lambda |
| 高阶函数 | 支持 | 支持 + 迭代器链 | Stream API |
Go 闭包:
func counter() func() int {
n := 0
return func() int {
n++
return n
}
}
Rust 闭包:
let add_one = |x: i32| x + 1;
let mut counter = 0;
let mut inc = || { counter += 1; counter };
Java Lambda:
Function<Integer, Integer> addOne = x -> x + 1;
Supplier<Integer> counter = new Supplier<>() {
int n = 0;
public Integer get() { return ++n; }
};
8. 复合类型:数组、切片、集合
8.1 数组
| 特性 | Go | Rust | Java |
|---|---|---|---|
| 固定长度数组 | [n]T |
[T; n] |
T[](长度运行时) |
| 长度属性 | len(arr) |
arr.len() |
arr.length |
| 越界 | 运行时 panic | 编译/运行时检查 | ArrayIndexOutOfBoundsException |
Go:
var a [3]int = [3]int{1, 2, 3}
b := [...]int{1, 2, 3}
Rust:
let a: [i32; 3] = [1, 2, 3];
let b = [0; 5]; // [0,0,0,0,0]
Java:
int[] a = {1, 2, 3};
int[] b = new int[5];
8.2 动态数组 / 切片
| 概念 | Go | Rust | Java |
|---|---|---|---|
| 动态数组 | slice []T |
Vec Vec<T> |
ArrayList List<T> |
| 创建 | make([]int, 0, 10) / []int{} |
Vec::new() / vec![] |
new ArrayList<>() |
| 追加 | append(s, v) |
vec.push(v) |
list.add(v) |
| 长度/容量 | len / cap |
len / capacity |
size() |
Go:
s := []int{1, 2, 3}
s = append(s, 4)
sub := s[1:3] // 切片共享底层数组
Rust:
let mut v = vec![1, 2, 3];
v.push(4);
let sub = &v[1..3];
Java:
List<Integer> list = new ArrayList<>(List.of(1, 2, 3));
list.add(4);
List<Integer> sub = list.subList(1, 3);
8.3 映射(字典)
Go:
m := map[string]int{"a": 1, "b": 2}
m["c"] = 3
v, ok := m["d"] // ok=false 表示不存在
delete(m, "a")
Rust:
use std::collections::HashMap;
let mut m = HashMap::new();
m.insert("a", 1);
if let Some(v) = m.get("a") { println!("{v}"); }
Java:
Map<String, Integer> m = new HashMap<>();
m.put("a", 1);
int v = m.getOrDefault("d", 0);
m.remove("a");
8.4 集合对比总表
| 数据结构 | Go | Rust | Java |
|---|---|---|---|
| 动态数组 | slice |
Vec<T> |
ArrayList<T> |
| 链表 | container/list |
LinkedList<T> |
LinkedList<T> |
| 哈希表 | map[K]V |
HashMap<K,V> |
HashMap<K,V> |
| 有序映射 | — | BTreeMap |
TreeMap |
| 集合 | map[T]struct{} |
HashSet<T> |
HashSet<T> |
| 队列 | chan / slice |
VecDeque |
Queue / Deque |
| 栈 | slice | Vec(push/pop) |
Deque / Stack(遗留) |
9. 结构体、类与面向对象
9.1 定义自定义类型
Go — struct:
type Person struct {
Name string
Age int
}
// 字面量
p := Person{Name: "Alice", Age: 30}
p2 := Person{"Bob", 25} // 按字段顺序
// 嵌入(组合,非继承)
type Employee struct {
Person // 匿名字段嵌入
EmployeeID int
}
Rust — struct:
struct Person {
name: String,
age: u32,
}
let p = Person {
name: "Alice".into(),
age: 30,
};
// 元组结构体
struct Point(f64, f64);
// 单元结构体
struct Marker;
Java — class:
public class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() { return name; }
public void setName(String name) { this.name = name; }
}
// Java 16+ record(不可变数据载体)
public record PersonRecord(String name, int age) {}
9.2 构造方式
| 语言 | 构造机制 |
|---|---|
| Go | 结构体字面量,无构造函数;可用工厂函数 NewXxx() |
| Rust | 结构体字面量 + impl 中的 new() 惯用法 |
| Java | 构造函数 + new 关键字 + Builder 模式 |
Go 工厂函数惯用法:
func NewPerson(name string, age int) *Person {
return &Person{Name: name, Age: age}
}
Rust new 惯用法:
impl Person {
fn new(name: impl Into<String>, age: u32) -> Self {
Self { name: name.into(), age }
}
}
9.3 继承 vs 组合
| 特性 | Go | Rust | Java |
|---|---|---|---|
| 类继承 | ❌ | ❌ | ✅ 单继承 |
| 接口/Trait | ✅ interface |
✅ trait |
✅ interface(多实现) |
| 组合 | ✅ struct 嵌入 | ✅ 字段组合 | ✅ 成员对象 |
| 方法重写 | 无继承,接口实现 | Trait 实现 | @Override |
Java 继承:
public class Dog extends Animal {
@Override
public void speak() {
System.out.println("Woof!");
}
}
Go/Rust 用组合 + 接口/Trait 替代继承(详见第 10 节)。
9.4 访问控制
| 级别 | Go | Rust | Java |
|---|---|---|---|
| 私有 | 小写字母开头 | 默认私有 | private |
| 包/模块内 | 同包可见(大写导出) | pub(crate) |
包级默认 |
| 受保护 | 无 | pub(super) |
protected |
| 公开 | 大写字母开头 | pub |
public |
Go 用首字母大小写控制导出,是三者中最简洁也最"非常规"的方案。
10. 接口、Trait 与多态
10.1 定义行为契约
Go — 隐式实现 interface:
type Shape interface {
Area() float64
Perimeter() float64
}
type Circle struct { Radius float64 }
func (c Circle) Area() float64 {
return math.Pi * c.Radius * c.Radius
}
func (c Circle) Perimeter() float64 {
return 2 * math.Pi * c.Radius
}
// Circle 自动满足 Shape,无需显式声明
Rust — 显式 impl trait:
trait Shape {
fn area(&self) -> f64;
fn perimeter(&self) -> f64;
}
struct Circle { radius: f64 }
impl Shape for Circle {
fn area(&self) -> f64 {
std::f64::consts::PI * self.radius * self.radius
}
fn perimeter(&self) -> f64 {
2.0 * std::f64::consts::PI * self.radius
}
}
Java — 显式 implements:
public interface Shape {
double area();
double perimeter();
}
public class Circle implements Shape {
private double radius;
public double area() { return Math.PI * radius * radius; }
public double perimeter() { return 2 * Math.PI * radius; }
}
10.2 多态机制对比
| 特性 | Go | Rust | Java |
|---|---|---|---|
| 实现方式 | 隐式满足接口 | 显式 impl Trait for Type |
显式 implements |
| 动态分发 | interface 值(底层 itable) |
dyn Trait(trait object) |
接口引用(vtable) |
| 静态分发 | 泛型约束 | 泛型 + Trait bound | 泛型 <T extends X> |
| 默认实现 | ❌(可用嵌入接口变通) | ✅ trait 默认方法 | ✅ default 方法(8+) |
| 关联类型 | ❌ | ✅ type Item |
❌(用泛型参数) |
Go 动态分发:
func printArea(s Shape) {
fmt.Println(s.Area())
}
Rust 动态分发:
fn print_area(s: &dyn Shape) {
println!("{}", s.area());
}
Java 动态分发:
void printArea(Shape s) {
System.out.println(s.area());
}
10.3 相同点与差异
相同点:
- 三者都支持基于行为的抽象,解耦调用方与实现方。
- 都可用接口/Trait 实现依赖倒置。
差异:
- Go 的"鸭子类型"在编译期检查:只要方法集匹配即实现接口,无需声明。
- Rust 的 Trait 最强大:支持关联类型、默认实现、运算符重载、扩展方法。
- Java 的接口在 8+ 后可有
default/static方法,最接近 Rust trait 默认实现。
11. 枚举与代数数据类型
11.1 枚举定义
Go — 用 const + iota 模拟:
type Status int
const (
StatusPending Status = iota
StatusActive
StatusClosed
)
// Go 1.18+ 可用 type Status string + const
Rust — 强大 enum:
enum Status {
Pending,
Active,
Closed,
}
// 带数据的枚举(代数数据类型 ADT)
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
ChangeColor(u8, u8, u8),
}
// Option 和 Result 本质是枚举
enum Option<T> {
Some(T),
None,
}
Java — enum:
public enum Status {
PENDING, ACTIVE, CLOSED;
public boolean isActive() {
return this == ACTIVE;
}
}
// Java 16+ sealed class 更接近 Rust ADT
public sealed interface Shape permits Circle, Rectangle {}
public final class Circle implements Shape {
public final double radius;
public Circle(double radius) { this.radius = radius; }
}
11.2 对比
| 特性 | Go | Rust | Java |
|---|---|---|---|
| 原生 enum | 弱(iota 模拟) | ✅ 强大 ADT | ✅ 枚举类 |
| 携带数据 | 需额外 struct | ✅ 变体直接携带 | sealed class / record |
| 模式匹配 | switch + type switch |
match 穷尽 |
switch 模式(21+) |
| Option 类型 | 无(用指针 nil 或多返回值) | Option<T> |
Optional<T> |
Rust match 解构:
match msg {
Message::Quit => println!("quit"),
Message::Move { x, y } => println!("move to {x},{y}"),
Message::Write(text) => println!("text: {text}"),
Message::ChangeColor(r, g, b) => println!("color: {r},{g},{b}"),
}
12. 错误处理
这是三者差异最大的领域之一。
12.1 哲学对比
| 语言 | 机制 | 哲学 |
|---|---|---|
| Go | 返回 (T, error) |
错误是值,显式处理 |
| Rust | Result<T, E> + ? 运算符 |
类型系统强制处理 |
| Java | 受检/非受检异常 | 异常可向上传播 |
12.2 代码对照
Go:
func readConfig(path string) (*Config, error) {
data, err := os.ReadFile(path)
if err != nil {
return nil, fmt.Errorf("read config: %w", err)
}
var cfg Config
if err := json.Unmarshal(data, &cfg); err != nil {
return nil, err
}
return &cfg, nil
}
// 调用方
cfg, err := readConfig("config.json")
if err != nil {
log.Fatal(err)
}
Rust:
fn read_config(path: &str) -> Result<Config, Box<dyn std::error::Error>> {
let data = std::fs::read(path)?;
let cfg: Config = serde_json::from_slice(&data)?;
Ok(cfg)
}
// 调用方
let cfg = read_config("config.json")?;
// 或
match read_config("config.json") {
Ok(cfg) => { /* use cfg */ }
Err(e) => eprintln!("error: {e}"),
}
Java:
public Config readConfig(String path) throws IOException {
String data = Files.readString(Path.of(path));
return objectMapper.readValue(data, Config.class);
}
// 调用方
try {
Config cfg = readConfig("config.json");
} catch (IOException e) {
throw new RuntimeException("read config failed", e);
}
12.3 panic / 不可恢复错误
| 语言 | 机制 |
|---|---|
| Go | panic() + recover()(少用,多用于程序级错误) |
| Rust | panic!() / unwrap() / expect() |
| Java | 未捕获异常导致线程终止 |
Go recover:
defer func() {
if r := recover(); r != nil {
fmt.Println("recovered:", r)
}
}()
panic("something went wrong")
12.4 错误处理对比表
| 特性 | Go | Rust | Java |
|---|---|---|---|
| 错误作为类型 | error 接口 |
Result<T,E> |
Exception 层次 |
| 强制处理 | ❌ 可忽略 _ |
✅ 编译器检查 | 受检异常强制 |
| 错误链 | fmt.Errorf("...: %w", err) |
source() / anyhow |
initCause() |
| 自定义错误 | 实现 Error() 方法 |
实现 std::error::Error |
继承 Exception |
| 早返回语法 | 手动 if err != nil |
? 运算符 |
throw |
13. 泛型
13.1 基本语法
Go(1.18+):
func Max[T constraints.Ordered](a, b T) T {
if a > b {
return a
}
return b
}
type Stack[T any] struct {
items []T
}
func (s *Stack[T]) Push(v T) {
s.items = append(s.items, v)
}
Rust:
fn max<T: Ord>(a: T, b: T) -> T {
if a > b { a } else { b }
}
struct Stack<T> {
items: Vec<T>,
}
impl<T> Stack<T> {
fn push(&mut self, v: T) {
self.items.push(v);
}
}
Java:
public static <T extends Comparable<T>> T max(T a, T b) {
return a.compareTo(b) > 0 ? a : b;
}
public class Stack<T> {
private List<T> items = new ArrayList<>();
public void push(T v) { items.add(v); }
}
13.2 泛型对比
| 特性 | Go | Rust | Java |
|---|---|---|---|
| 引入版本 | 1.18(2022) | 1.0 起不断完善 | 5(2004) |
| 类型约束 | interface 约束 |
Trait bound |
extends 边界 |
| 类型擦除 | 单态化(非擦除) | 单态化 | 擦除(运行时) |
| 通配符 | 无 | 无 | ? extends T / ? super T |
| 关联类型 | 无 | type Item |
无 |
| 特化 | 单态化实例化 | 单态化实例化 | 类型擦除 + 装箱 |
Rust Trait bound 示例:
fn print_debug<T: std::fmt::Debug>(val: T) {
println!("{:?}", val);
}
// where 子句
fn complex<T, U>(t: T, u: U) -> String
where
T: std::fmt::Display + Clone,
U: std::fmt::Debug,
{
format!("{} {:?}", t, u)
}
Java 通配符:
// 生产者 extends,消费者 super(PECS 原则)
List<? extends Number> nums;
List<? super Integer> ints;
14. 包、模块与可见性
14.1 组织方式
Go:
myproject/
├── go.mod
├── main.go
└── pkg/
└── utils/
└── helper.go // package utils
// go.mod
module github.com/user/myproject
// 导入
import "github.com/user/myproject/pkg/utils"
Rust:
myproject/
├── Cargo.toml
└── src/
├── main.rs
├── lib.rs
└── utils/
└── mod.rs
// Cargo.toml
[package]
name = "myproject"
// 模块声明
mod utils;
use crate::utils::helper;
Java:
src/main/java/
└── com/example/
├── Main.java
└── utils/
└── Helper.java
package com.example.utils;
import com.example.Main;
14.2 包管理对比
| 特性 | Go | Rust | Java |
|---|---|---|---|
| 包管理器 | Go Modules | Cargo | Maven / Gradle |
| 依赖文件 | go.mod / go.sum |
Cargo.toml / Cargo.lock |
pom.xml / build.gradle |
| 构建命令 | go build / go run |
cargo build / cargo run |
mvn package / gradle build |
| 标准布局 | $GOPATH 已弱化,模块路径 |
src/ + Cargo.toml |
src/main/java |
15. 内存管理与指针
15.1 核心机制
| 语言 | 内存管理 | 手动释放 |
|---|---|---|
| Go | GC 自动回收 | ❌ |
| Rust | 所有权 + 借用 + 生命周期(无 GC) | 编译期自动 drop |
| Java | JVM GC | ❌(可 weak/phantom 引用) |
15.2 指针 / 引用
Go:
x := 42
p := &x // 取地址
fmt.Println(*p) // 解引用
// 但没有指针运算
Rust:
let x = 42;
let r = &x; // 不可变借用
let m = &mut x; // 可变借用(x 必须是 mut)
// 所有权转移
let s = String::from("hello");
let s2 = s; // s 不再可用
Java:
// 所有对象变量都是引用,无显式指针
String s = "hello";
String s2 = s; // 共享引用,非拷贝
// 无 & 和 * 运算符
15.3 Rust 所有权规则(Go/Java 无对应概念)
- 每个值有且仅有一个所有者。
- 所有者离开作用域,值被 drop(自动释放)。
- 同一时刻:多个不可变借用 或 一个可变借用(不能并存)。
let mut s = String::from("hello");
let r1 = &s; // OK
let r2 = &s; // OK
// let r3 = &mut s; // 编译错误!已有不可变借用
15.4 智能指针 / 共享所有权
| 语言 | 机制 |
|---|---|
| Go | 指针 + GC,无需智能指针 |
| Rust | Box<T> Rc<T> Arc<T> RefCell<T> |
| Java | 普通引用 + GC;无原生智能指针 |
16. 并发编程
16.1 基本模型
| 语言 | 轻量线程 | 同步原语 | 消息传递 |
|---|---|---|---|
| Go | goroutine | sync.Mutex WaitGroup |
channel |
| Rust | std::thread + async |
Mutex RwLock |
mpsc::channel |
| Java | Thread / 虚拟线程(21+) |
synchronized Lock |
BlockingQueue |
16.2 代码对照
Go — goroutine + channel:
ch := make(chan int, 10)
go func() {
ch <- 42
}()
v := <-ch
fmt.Println(v)
// WaitGroup
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
wg.Add(1)
go func(n int) {
defer wg.Done()
fmt.Println(n)
}(i)
}
wg.Wait()
Rust — thread + channel:
use std::sync::mpsc;
use std::thread;
let (tx, rx) = mpsc::channel();
thread::spawn(move || {
tx.send(42).unwrap();
});
let v = rx.recv().unwrap();
// async/await(Tokio 运行时)
// async fn fetch() -> Result<String, Error> { ... }
// let result = fetch().await?;
Java — 虚拟线程 + CompletableFuture:
// Java 21 虚拟线程
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
Future<Integer> f = executor.submit(() -> 42);
System.out.println(f.get());
}
// CompletableFuture
CompletableFuture.supplyAsync(() -> 42)
.thenApply(v -> v * 2)
.thenAccept(System.out::println);
16.3 并发对比
| 特性 | Go | Rust | Java |
|---|---|---|---|
| 轻量并发 | goroutine(极轻) | async task(需运行时) | 虚拟线程(21+) |
| CSP 模型 | channel 是一等公民 | channel 有,但更常用消息传递库 | 无原生 CSP |
| 数据竞争 | 靠约定 + race detector | 编译期拒绝(Send/Sync) | 靠 synchronized/Lock |
| 共享内存 | sync.Mutex |
Mutex<T> / RwLock<T> |
synchronized / ReentrantLock |
| 错误处理 | channel 关闭检测 | RecvError |
阻塞异常 |
关键差异:
- Go 的 goroutine 是语言内置、极简的并发原语,
go func()即可启动。 - Rust 在编译期通过
Send/Synctrait 防止数据竞争,最安全但约束最多。 - Java 传统线程重,Java 21 虚拟线程大幅改善;生态以
java.util.concurrent为主。
17. 字符串处理
17.1 拼接
Go:
s := "Hello" + " " + "World"
s = fmt.Sprintf("%s %s", "Hello", "World")
var b strings.Builder
b.WriteString("Hello")
b.WriteString(" World")
Rust:
let s = format!("{} {}", "Hello", "World");
let s2 = ["Hello", " ", "World"].concat();
Java:
String s = "Hello" + " " + "World";
String s2 = String.format("%s %s", "Hello", "World");
String s3 = String.join(" ", "Hello", "World");
17.2 常用操作
| 操作 | Go | Rust | Java |
|---|---|---|---|
| 长度 | len(s)(字节数) |
s.len()(字节)/ s.chars().count() |
s.length()(char 数) |
| 切片/子串 | s[start:end] |
&s[start..end] |
s.substring(start, end) |
| 包含 | strings.Contains(s, sub) |
s.contains(sub) |
s.contains(sub) |
| 分割 | strings.Split(s, sep) |
s.split(sep) |
s.split(sep) |
| 格式化 | fmt.Sprintf |
format! |
String.format |
18. 注解、属性与元编程
| 特性 | Go | Rust | Java |
|---|---|---|---|
| 元数据注解 | 无内置注解(用 struct tag) | #[attribute] |
@Annotation |
| 反射 | reflect 包(有限) |
有限(std::any::TypeId) |
强大 java.lang.reflect |
| 编译期宏 | 无 | 宏系统(macro_rules! / proc macro) |
注解处理器(APT) |
| 代码生成 | go generate |
宏 / build.rs | Lombok / APT |
Go struct tag:
type User struct {
Name string `json:"name" db:"user_name"`
}
Rust attribute:
#[derive(Debug, Clone, Serialize, Deserialize)]
struct User {
name: String,
}
Java annotation:
@JsonProperty("name")
@Column(name = "user_name")
private String name;
19. 测试
Go:
// math_test.go
func TestAdd(t *testing.T) {
got := Add(2, 3)
if got != 5 {
t.Errorf("Add(2,3) = %d; want 5", got)
}
}
// go test ./...
Rust:
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_add() {
assert_eq!(add(2, 3), 5);
}
}
// cargo test
Java:
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
class MathTest {
@Test
void testAdd() {
assertEquals(5, add(2, 3));
}
}
// mvn test
| 特性 | Go | Rust | Java |
|---|---|---|---|
| 测试文件位置 | *_test.go 同包 |
#[cfg(test)] 模块 |
src/test/java |
| 基准测试 | BenchmarkXxx(b *testing.B) |
#[bench](nightly)/ criterion |
JMH |
| 表格驱动测试 | 惯用法(slice of cases) | 惯用法 | @ParameterizedTest |
20. 综合对比速查表
20.1 语法元素速查
| 语法元素 | Go | Rust | Java |
|---|---|---|---|
| 输出 | fmt.Println |
println! |
System.out.println |
| 变量声明 | x := 1 / var x int |
let x = 1 / let mut x |
int x = 1 |
| 常量 | const |
const / static |
final |
| 空值 | nil |
None |
null |
| 条件 | if |
if(表达式) |
if |
| 分支 | switch |
match |
switch |
| 循环 | for only |
loop / while / for |
for / while |
| 函数 | func f() |
fn f() |
void f() / 方法 |
| 类/结构 | struct |
struct |
class |
| 接口 | interface |
trait |
interface |
| 枚举 | const + iota |
enum |
enum |
| 错误 | error 返回值 |
Result<T,E> |
Exception |
| 泛型 | [T any] |
<T: Trait> |
<T extends X> |
| 包 | package + import |
mod + use |
package + import |
| 并发 | go + chan |
thread / async |
Thread / VirtualThread |
20.2 优劣势一句话
| 语言 | 最适合 | 主要代价 |
|---|---|---|
| Go | 云原生、微服务、高并发网络服务 | 泛型/表达力相对弱,错误处理繁琐 |
| Rust | 系统编程、性能敏感、安全关键场景 | 学习曲线陡,编译慢,开发速度慢 |
| Java | 企业应用、Android、大型生态项目 | JVM 开销,语法相对冗长 |
20.3 从 X 迁移到 Y 的快速提示
Java → Go:
- 放下继承,改用组合 + interface。
- 习惯没有异常,处处
if err != nil。 - 习惯
:=短声明和首字母导出规则。
Java → Rust:
- 放下 null,拥抱
Option<T>。 - 放下异常,拥抱
Result<T, E>和?。 - 理解所有权/借用是核心,不是可选项。
Go → Rust:
- 多返回值升级为
Result。 - 接口升级为 Trait(需显式 impl)。
- GC 消失,需主动管理所有权。
Go → Java:
- 习惯类和访问修饰符。
- 用
ArrayList/HashMap替代 slice/map。 - 异常替代 error 返回值。
附录:同一功能三语言完整示例
实现:读取用户列表,过滤成年人,按名字排序后输出。
Go:
package main
import (
"fmt"
"sort"
)
type User struct {
Name string
Age int
}
func main() {
users := []User{
{"Bob", 17},
{"Alice", 30},
{"Charlie", 25},
}
var adults []User
for _, u := range users {
if u.Age >= 18 {
adults = append(adults, u)
}
}
sort.Slice(adults, func(i, j int) bool {
return adults[i].Name < adults[j].Name
})
for _, u := range adults {
fmt.Printf("%s (%d)\n", u.Name, u.Age)
}
}
Rust:
#[derive(Debug)]
struct User {
name: String,
age: u32,
}
fn main() {
let users = vec![
User { name: "Bob".into(), age: 17 },
User { name: "Alice".into(), age: 30 },
User { name: "Charlie".into(), age: 25 },
];
let mut adults: Vec<_> = users
.into_iter()
.filter(|u| u.age >= 18)
.collect();
adults.sort_by(|a, b| a.name.cmp(&b.name));
for u in &adults {
println!("{} ({})", u.name, u.age);
}
}
Java:
import java.util.Comparator;
import java.util.List;
public class Main {
record User(String name, int age) {}
public static void main(String[] args) {
List<User> users = List.of(
new User("Bob", 17),
new User("Alice", 30),
new User("Charlie", 25)
);
users.stream()
.filter(u -> u.age() >= 18)
.sorted(Comparator.comparing(User::name))
.forEach(u -> System.out.printf("%s (%d)%n", u.name(), u.age()));
}
}
文档版本:2026-07 | 如有语言版本更新导致语法差异,请以各语言官方文档为准。
更多推荐


所有评论(0)