一举两得:Go和Rust同步学习指南_rust和golang
myzbx 2025-09-06 08:23 6 浏览
变量与常量
变量声明
Go
// 显式类型声明
var x int = 10
// 类型推断
var y = 20
z := 30 // 短变量声明,只能在函数内使用
// 批量声明
var (
a int
b string = "hello"
c = 3.14
)
// 默认值
var zeroInt int // 0
var zeroStr string // ""
var zeroBool bool // false
Rust
// 不可变变量(默认)
let x: i32 = 10;
// 类型推断
let y = 20;
// 可变变量
let mut z = 30;
z = 40; // 只有mut变量可以修改
// 变量遮蔽(shadowing)
let a = 5;
let a = a + 1; // 允许同名变量,创建新绑定
// 常量(必须显式类型)
const PI: f64 = 3.14159;
// 默认不可变是Rust的重要安全特性
基本数据类型
整数类型
Go
var i8 int8 = -128
var u8 uint8 = 255
var i16 int16 = -32768
var u16 uint16 = 65535
var i32 int32 = -2147483648
var u32 uint32 = 4294967295
var i64 int64 = -9223372036854775808
var u64 uint64 = 18446744073709551615
var i int // 平台相关,32或64位
var u uint // 平台相关
var r rune = '中' // int32的别名
var b byte = 255 // uint8的别名
Rust
let i8: i8 = -128;
let u8: u8 = 255;
let i16: i16 = -32768;
let u16: u16 = 65535;
let i32: i32 = -2147483648;
let u32: u32 = 4294967295;
let i64: i64 = -9223372036854775808;
let u64: u64 = 18446744073709551615;
let isize: isize = -1; // 平台相关
let usize: usize = 1; // 平台相关
let char = '中'; // Unicode标量值,4字节
浮点类型
Go
var f32 float32 = 3.14
var f64 float64 = 3.141592653589793
Rust
let f32: f32 = 3.14;
let f64: f64 = 3.141592653589793;
布尔类型
Go
var b1 bool = true
var b2 = false
Rust
let b1: bool = true;
let b2 = false;
字符串类型
Go
// 字符串是不可变的字节序列
var s1 string = "hello"
s2 := "world"
// 原始字符串(不转义)
s3 := `line 1
line 2\n` // \n不会被转义
// 字符串拼接
s4 := s1 + " " + s2
Rust
// 字符串切片(不可变引用)
let s1: &str = "hello";
// String类型(可增长、可修改)
let mut s2 = String::from("world");
// 原始字符串
let s3 = r"line 1\nline 2"; // \n不会被转义
let s4 = r#"字符串可以包含"引号""#;
// 字符串拼接
let s5 = format!("{} {}", s1, s2); // 创建新String
s2.push_str("!"); // 修改现有String
控制结构
条件语句
Go
// 基本if
if x > 0 {
fmt.Println("positive")
}
// if with short statement
if y := compute(); y < 0 {
fmt.Println("negative")
} else if y == 0 {
fmt.Println("zero")
} else {
fmt.Println("positive")
}
// switch
switch os := runtime.GOOS; os {
case "darwin":
fmt.Println("macOS")
case "linux":
fmt.Println("Linux")
default:
fmt.Printf("%s\n", os)
}
// 无条件的switch(相当于if-else链)
switch {
case x < 0:
fmt.Println("negative")
case x == 0:
fmt.Println("zero")
default:
fmt.Println("positive")
}
Rust
// 基本if
if x > 0 {
println!("positive");
}
// if-else if-else
let y = compute();
if y < 0 {
println!("negative");
} else if y == 0 {
println!("zero");
} else {
println!("positive");
}
// if是表达式
let result = if y > 0 { "positive" } else { "non-positive" };
// match(比switch更强大)
match x.cmp(&0) {
std::cmp::Ordering::Less => println!("negative"),
std::cmp::Ordering::Equal => println!("zero"),
std::cmp::Ordering::Greater => println!("positive"),
}
// match是表达式
let number = match x {
1 => "one",
2 => "two",
3..=9 => "three to nine", // 范围匹配
_ => "other", // 默认情况
};
循环
Go
// 传统for循环
for i := 0; i < 10; i++ {
fmt.Println(i)
}
// while循环(用for实现)
j := 0
for j < 10 {
fmt.Println(j)
j++
}
// 无限循环
for {
if condition {
break
}
}
// range循环
nums := []int{1, 2, 3}
for i, num := range nums {
fmt.Printf("index: %d, value: %d\n", i, num)
}
// 带标签的break
OuterLoop:
for i := 0; i < 10; i++ {
for j := 0; j < 10; j++ {
if i*j > 50 {
break OuterLoop
}
}
}
Rust
// for循环(迭代器)
for i in 0..10 { // 0..10是范围,不包括10
println!("{}", i);
}
// while循环
let mut j = 0;
while j < 10 {
println!("{}", j);
j += 1;
}
// 无限循环(可返回值)
let result = loop {
if condition {
break 42; // 返回42
}
};
// 迭代集合
let nums = vec![1, 2, 3];
for (i, &num) in nums.iter().enumerate() {
println!("index: {}, value: {}", i, num);
}
// 带标签的break
'outer: for i in 0..10 {
for j in 0..10 {
if i * j > 50 {
break 'outer;
}
}
}
函数
基本函数
Go
// 基本函数
func add(a int, b int) int {
return a + b
}
// 参数类型简写
func sub(a, b int) int {
return a - b
}
// 多返回值
func swap(a, b string) (string, string) {
return b, a
}
// 命名返回值
func split(sum int) (x, y int) {
x = sum * 4 / 9
y = sum - x
return // 裸返回
}
// 可变参数
func sum(nums ...int) int {
total := 0
for _, num := range nums {
total += num
}
return total
}
Rust
// 基本函数
fn add(a: i32, b: i32) -> i32 {
a + b // 没有分号,这是表达式
}
// 多返回值(使用元组)
fn swap(a: String, b: String) -> (String, String) {
(b, a)
}
// 表达式与语句
fn five() -> i32 {
5 // 表达式返回
}
fn plus_one(x: i32) -> i32 {
x + 1 // 表达式返回
// x + 1; // 加上分号变成语句,会报错
}
// 可变参数(使用切片)
fn sum(nums: &[i32]) -> i32 {
nums.iter().sum()
}
// 方法(关联函数)
impl Point {
fn distance(&self, other: &Point) -> f64 {
// 方法实现
}
}
闭包(匿名函数)
Go
// 基本闭包
add := func(a, b int) int {
return a + b
}
result := add(1, 2)
// 闭包捕获环境变量
x := 10
closure := func() int {
return x * 2 // 捕获x
}
fmt.Println(closure()) // 20
Rust
// 基本闭包
let add = |a: i32, b: i32| -> i32 { a + b };
let result = add(1, 2);
// 类型推断
let add = |a, b| a + b; // 编译器能推断类型
// 捕获环境变量
let x = 10;
let closure = || x * 2; // 不可变借用x
println!("{}", closure()); // 20
// 移动语义(强制获取所有权)
let s = String::from("hello");
let closure = move || println!("{}", s); // s的所有权被移动
closure();
// println!("{}", s); // 错误!s已被移动
复合数据类型
数组
Go
// 数组(固定长度)
var a [3]int = [3]int{1, 2, 3}
b := [...]int{1, 2, 3} // 编译器推断长度
// 访问元素
first := a[0]
// 修改元素
a[1] = 20
// 遍历
for i, v := range a {
fmt.Printf("index: %d, value: %d\n", i, v)
}
// 多维数组
var matrix [2][3]int = [2][3]int{
{1, 2, 3},
{4, 5, 6},
}
Rust
// 数组(固定长度)
let a: [i32; 3] = [1, 2, 3];
let b = [1, 2, 3]; // 类型推断
// 访问元素
let first = a[0];
// 修改元素(需要mut)
let mut c = [1, 2, 3];
c[1] = 20;
// 遍历
for (i, &v) in a.iter().enumerate() {
println!("index: {}, value: {}", i, v);
}
// 多维数组
let matrix: [[i32; 3]; 2] = [
[1, 2, 3],
[4, 5, 6],
];
切片/向量
Go
// 切片(动态大小视图)
s := []int{1, 2, 3} // 切片字面量
var s2 []int // 零值是nil
// 从数组创建切片
arr := [5]int{1, 2, 3, 4, 5}
slice := arr[1:4] // [2, 3, 4]
// 修改切片会影响底层数组
slice[0] = 20
fmt.Println(arr) // [1, 20, 3, 4, 5]
// 常用操作
s = append(s, 4) // 追加
length := len(s) // 长度
capacity := cap(s) // 容量
sub := s[1:3] // 子切片
copy(sub, []int{9,8}) // 复制
// make创建切片
s3 := make([]int, 5) // 长度5,容量5
s4 := make([]int, 0, 10) // 长度0,容量10
Rust
// 切片(不可变视图)
let arr = [1, 2, 3, 4, 5];
let slice: &[i32] = &arr[1..4]; // [2, 3, 4]
// 向量(Vec,可增长数组)
let mut vec = vec![1, 2, 3];
vec.push(4); // 追加
let first = vec[0]; // 访问
vec[1] = 20; // 修改
// 常用操作
let len = vec.len(); // 长度
let cap = vec.capacity(); // 容量
let sub = &vec[1..3]; // 子切片
vec.extend([5,6]); // 扩展
vec.insert(1, 10); // 插入
vec.remove(2); // 移除
// 迭代
for v in &vec {
println!("{}", v);
}
结构体
Go
// 定义结构体
type Person struct {
Name string
Age int
}
// 创建实例
p1 := Person{"Alice", 30}
p2 := Person{Name: "Bob", Age: 25}
// 匿名结构体
p3 := struct {
Name string
Age int
}{
Name: "Charlie",
Age: 35,
}
// 方法
func (p Person) Greet() string {
return fmt.Sprintf("Hello, my name is %s", p.Name)
}
// 指针接收者方法(可修改结构体)
func (p *Person) Birthday() {
p.Age++
}
// 嵌套结构体
type Employee struct {
Person
JobTitle string
}
Rust
// 定义结构体
struct Person {
name: String,
age: i32,
}
// 创建实例
let p1 = Person {
name: String::from("Alice"),
age: 30,
};
// 更新语法
let p2 = Person {
name: String::from("Bob"),
..p1 // 使用p1的其他字段
};
// 元组结构体
struct Color(i32, i32, i32);
let black = Color(0, 0, 0);
// 方法
impl Person {
fn greet(&self) -> String {
format!("Hello, my name is {}", self.name)
}
fn birthday(&mut self) {
self.age += 1;
}
// 关联函数(类似静态方法)
fn new(name: String, age: i32) -> Self {
Person { name, age }
}
}
// 嵌套结构体
struct Employee {
person: Person,
job_title: String,
}
枚举
Go
// Go没有原生枚举,通常用常量模拟
type Direction int
const (
North Direction = iota
East
South
West
)
func (d Direction) String() string {
return [...]string{"North", "East", "South", "West"}[d]
}
// 带值的枚举(使用结构体和接口)
type Shape interface {
area() float64
}
type Circle struct {
Radius float64
}
func (c Circle) area() float64 {
return math.Pi * c.Radius * c.Radius
}
type Rectangle struct {
Width, Height float64
}
func (r Rectangle) area() float64 {
return r.Width * r.Height
}
Rust
// 基本枚举
enum Direction {
North,
East,
South,
West,
}
// 带数据的枚举
enum Shape {
Circle(f64), // 半径
Rectangle(f64, f64), // 宽和高
Square(f64), // 边长
}
// 方法
impl Shape {
fn area(&self) -> f64 {
match self {
Shape::Circle(r) => std::f64::consts::PI * r * r,
Shape::Rectangle(w, h) => w * h,
Shape::Square(s) => s * s,
}
}
}
// Option枚举(标准库)
enum Option<T> {
Some(T),
None,
}
// Result枚举(标准库)
enum Result<T, E> {
Ok(T),
Err(E),
}
错误处理
Go
// 多返回值错误处理
func divide(a, b float64) (float64, error) {
if b == 0 {
return 0, fmt.Errorf("division by zero")
}
return a / b, nil
}
result, err := divide(10, 0)
if err != nil {
log.Fatal(err)
}
// 自定义错误类型
type MyError struct {
Msg string
Code int
}
func (e *MyError) Error() string {
return fmt.Sprintf("code %d: %s", e.Code, e.Msg)
}
func process() error {
return &MyError{"something went wrong", 500}
}
// panic和recover
func risky() {
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered:", r)
}
}()
panic("something bad happened")
}
Rust
// Result类型处理
fn divide(a: f64, b: f64) -> Result<f64, String> {
if b == 0.0 {
Err(String::from("division by zero"))
} else {
Ok(a / b)
}
}
match divide(10.0, 0.0) {
Ok(result) => println!("Result: {}", result),
Err(e) => println!("Error: {}", e),
}
// 更简洁的写法(使用?运算符)
fn calculate() -> Result<f64, String> {
let x = divide(10.0, 2.0)?; // 如果Err会提前返回
let y = divide(x, 3.0)?;
Ok(y)
}
// 自定义错误类型(更推荐的方式)
#[derive(Debug)]
enum MathError {
DivisionByZero,
NegativeLogarithm,
}
impl std::fmt::Display for MathError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
MathError::DivisionByZero => write!(f, "division by zero"),
MathError::NegativeLogarithm => write!(f, "logarithm of negative number"),
}
}
}
fn better_divide(a: f64, b: f64) -> Result<f64, MathError> {
if b == 0.0 {
Err(MathError::DivisionByZero)
} else {
Ok(a / b)
}
}
// panic和unwrap
let x: i32 = "123".parse().unwrap(); // 成功时返回值,失败时panic
let y: i32 = "abc".parse().expect("Failed to parse number"); // 自定义panic消息
并发编程
Go
// goroutine
go func() {
fmt.Println("Running in goroutine")
}()
// WaitGroup等待多个goroutine完成
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()
// channel通信
ch := make(chan int)
go func() {
ch <- 42 // 发送
}()
value := <-ch // 接收
// 缓冲channel
bufCh := make(chan int, 2)
bufCh <- 1
bufCh <- 2
// select多路复用
select {
case v := <-ch1:
fmt.Println(v)
case v := <-ch2:
fmt.Println(v)
case <-time.After(time.Second):
fmt.Println("timeout")
default:
fmt.Println("no activity")
}
// sync.Mutex互斥锁
var mu sync.Mutex
var counter int
for i := 0; i < 10; i++ {
go func() {
mu.Lock()
defer mu.Unlock()
counter++
}()
}
Rust
// 线程
let handle = std::thread::spawn(|| {
println!("Running in thread");
});
handle.join().unwrap(); // 等待线程结束
// 通道通信
let (tx, rx) = std::sync::mpsc::channel();
std::thread::spawn(move || {
tx.send(42).unwrap(); // 发送
});
let value = rx.recv().unwrap(); // 接收
// 共享状态并发(Arc + Mutex)
use std::sync::{Arc, Mutex};
let counter = Arc::new(Mutex::new(0));
let mut handles = vec![];
for _ in 0..10 {
let counter = Arc::clone(&counter);
let handle = std::thread::spawn(move || {
let mut num = counter.lock().unwrap();
*num += 1;
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
// async/await(异步编程)
async fn fetch_data() -> Result<String, reqwest::Error> {
reqwest::get("https://example.com")
.await?
.text()
.await
}
#[tokio::main]
async fn main() {
match fetch_data().await {
Ok(data) => println!("Got data: {}", data),
Err(e) => println!("Error: {}", e),
}
}
相关推荐
- 微信又双叒叕更新了!这次是安卓版
-
澎湃新闻综合报道近日安卓版微信正式更新了8.0.10版主要有四大更新日常使用起来会更加方便一起来看看吧1朋友圈视频封面在此之前,朋友圈背景一直只能放静态图片,但此次更新后,可以从视频号中选择一段...
- 镜子里的你和照片里的你,哪个更真实?
-
不知道大家有没有这样的经历。聚餐、团建……一群人拍合照,拍完之后,我们满心期待地放大照片,却惊慌失措地发现——怎么自己又被拍得这么丑!但这时,别人总是会说道——「这就是你平常的样子啊。」可是,我们平时...
- 歼20战斗机现身珠海,首次公开静态展示,体现解放军的自信和强大
-
日本航空自卫队在9月份举行了三泽基地开发日活动,期间出动12架F-35A闪电II战斗机进行了公开展示,不过仅仅是编队通场飞过而已。日本航空自卫队仅仅动用1架F-35A战斗机进行了机动飞行表演,从公开的...
- Java类初始化阶段深度解析:执行顺序与线程安全
-
一、初始化阶段核心机制二、分步详解与代码验证1.初始化触发条件主动使用场景:publicclassInitTrigger{static{System.out.pr...
- 深入剖析 Java 类加载机制:原理、优化与实践
-
作为Java开发者,你是否遇到过这样的场景:线上服务突然抛出NoClassDefFoundError,但本地调试却一切正常;或者明明引入了依赖JAR,却始终报ClassNotFoundExcep...
- SUID/SGID是啥?如何让普通用户拥有root的能力?
-
原文链接:「链接」在Linux系统中,权限控制是一项至关重要的安全机制。除了常见的r(读)、w(写)和x(执行)权限外,还有三种特殊权限位常被忽视:SUID(SetUserID)、SGID...
- 数码宝贝新世纪:SP奥米加兽AS情报泄露,是否也是强力辅助?
-
大家好!我是小飉[liáo],欢迎来阅!情怀手游《数码宝贝新世纪》官方不按套路出牌,这次公布的入围测试的人员名单,但是并没有公布SP奥米加兽AS的能力情报,还好广大网友给力。次日,在论坛,以及...
- 抽象类(abstract class)与接口(interface)
-
A.核心概念1.抽象类-定义:带有abstract修饰符的类,不能被实例化,用于定义一组方法签名和可选的部分公共实现。-特性:-可以包含字段、构造函数、已实现的方法(带方法体)和抽象方法(...
- S39结束时间确定,新赛季段位继承公布,大量皮肤在7月初集体上线
-
文/静海君如果说之前都还是猜测的话,那游戏内的一个变动,基本100%确定了新赛季(S40)的开启时间。新赛季的开启时间关于新赛季的开启时间,目前主要有两个线索。第一个关于新赛季开启时间的线索是「游戏内...
- 一篇文章掌握整个JVM,JVM超详细解析!!!
-
不懂JVM看完这一篇文章你就会非常懂了,文章很长,非常详细!!!先想想一些问题1我们开发人员编写的Java代码是怎么让电脑认识的首先先了解电脑是二进制的系统,他只认识01010101比如我们经常要...
- 项目用 JDK17 后,bug 少了、速度快了!这 4 个好处太实在
-
别再死守JDK8了!去年把电商项目升级到JDK17,团队直接爽翻:代码量少写1/3,大促再也不卡顿,运维半夜不call人,连测试都夸bug少了。今天就说真话,JDK17在项目里的4...
- 法定继承有顺序:在法定继承人中,谁应该优先继承?
-
免费问律师_法律咨询免费24小时律师在线解答-法临网“父母去世没留遗嘱,兄弟姐妹争遗产闹上法庭!”法定继承中,谁优先拿财产?《民法典》明确“顺序+份额”规则,一文说清关键点,避免家庭内耗!一、法定...
- 前端必会:ES5寄生继承 vs ES6 Class继承
-
大家好,我是谦!说到继承,估计不少前端开发者都踩过坑。尤其是在ES5到ES6的过渡阶段,我们写代码时常常被问到:“你用的是原型继承还是Class继承?”再加上面试官特别喜欢追问底层实现——...
- 子女入了外籍能否继承父母国内的房产呢?
-
大家好,这里是家理范律,专注遗产继承、婚姻家事领域!-很多加入外籍的朋友都纠结:自己还能继承国内父母的房产吗?答案是可以继承,但流程远比想象复杂!-真实案例:美籍华人张先生,拿着父母在加州公证的遗嘱回...
- J.A.C.S | 基于化学类型和靶点的基因组挖掘以寻找一种新的细菌肽脱甲酰酶天然产物抑制剂
-
大家好,今天推送的文章是2025年6月发表在JournaloftheAmericanChemicalSociety上的“Chemotype-andTarget-DrivenGenome...
- 一周热门
- 最近发表
- 标签列表
-
- HTML 简介 (30)
- HTML 响应式设计 (31)
- HTML URL 编码 (32)
- HTML Web 服务器 (31)
- HTML 表单属性 (32)
- HTML 音频 (31)
- HTML5 支持 (33)
- HTML API (36)
- HTML 总结 (32)
- HTML 全局属性 (32)
- HTML 事件 (31)
- HTML 画布 (32)
- HTTP 方法 (30)
- 键盘快捷键 (30)
- CSS 语法 (35)
- CSS 轮廓宽度 (31)
- CSS 谷歌字体 (33)
- CSS 链接 (31)
- CSS 定位 (31)
- CSS 图片库 (32)
- CSS 图像精灵 (31)
- SVG 文本 (32)
- 时钟启动 (33)
- HTML 游戏 (34)
- JS Loop For (32)