Golang、Rust、Java 基本语法对照

基于 Go 1.22+Rust 1.7x+Java 21+ 的现代版本编写。
面向需要在三种语言间切换、或从一门语言迁移到另一门的开发者。


目录

  1. 语言概览与设计理念
  2. 程序结构与入口
  3. 基本数据类型
  4. 变量、常量与可变性
  5. 运算符与表达式
  6. 控制流
  7. 函数与方法
  8. 复合类型:数组、切片、集合
  9. 结构体、类与面向对象
  10. 接口、Trait 与多态
  11. 枚举与代数数据类型
  12. 错误处理
  13. 泛型
  14. 包、模块与可见性
  15. 内存管理与指针
  16. 并发编程
  17. 字符串处理
  18. 注解、属性与元编程
  19. 测试
  20. 综合对比速查表

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() 可有多个函数/类型,mainmain.rslib.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
字符 runeint32,Unicode 码点) char(4 字节 Unicode 标量) char(2 字节 UTF-16 单元)
字节 byteuint8 别名) 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 TT::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:= 可在内层作用域遮蔽外层变量。
  • Javafinal 只限制引用/变量重新赋值,不保证对象内部不可变。

4.3 零值 / 默认值

语言 机制
Go 未初始化变量有零值0""nilfalse
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 Vecpush/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 无对应概念)

  1. 每个值有且仅有一个所有者
  2. 所有者离开作用域,值被 drop(自动释放)。
  3. 同一时刻:多个不可变借用 一个可变借用(不能并存)。
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/Sync trait 防止数据竞争,最安全但约束最多。
  • 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 | 如有语言版本更新导致语法差异,请以各语言官方文档为准。

Logo

中国智能体开发者社区,聚焦智能体与大模型开发,提供前沿资讯、实用工具链、开源项目及行业案例。通过技术沙龙、开发者大赛等活动,促进经验交流与协作,助力开发者快速构建创新智能应用。

更多推荐