一举两得:Go和Rust同步学习指南_go与rust
zhezhongyun 2025-09-04 22:08 14 浏览
变量与常量
变量声明
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),
}
}
相关推荐
- perl基础——循环控制_principle循环
-
在编程中,我们往往需要进行不同情况的判断,选择,重复操作。这些时候我们需要对简单语句来添加循环控制变量或者命令。if/unless我们需要在满足特定条件下再执行的语句,可以通过if/unle...
- CHAPTER 2 The Antechamber of M de Treville 第二章 特雷维尔先生的前厅
-
CHAPTER1TheThreePresentsofD'ArtagnantheElderCHAPTER2TheAntechamber...
- CHAPTER 5 The King'S Musketeers and the Cardinal'S Guards 第五章 国王的火枪手和红衣主教的卫士
-
CHAPTER3TheAudienceCHAPTER5TheKing'SMusketeersandtheCardinal'SGuard...
- CHAPTER 3 The Audience 第三章 接见
-
CHAPTER3TheAudienceCHAPTER3TheAudience第三章接见M.DeTrévillewasatt...
- 别搞印象流!数据说明谁才是外线防守第一人!
-
来源:Reddit译者:@assholeeric编辑:伯伦WhoarethebestperimeterdefendersintheNBA?Here'sagraphofStea...
- V-Day commemorations prove anti-China claims hollow
-
People'sLiberationArmyhonorguardstakepartinthemilitaryparademarkingthe80thanniversary...
- EasyPoi使用_easypoi api
-
EasyPoi的主要特点:1.设计精巧,使用简单2.接口丰富,扩展简单3.默认值多,writelessdomore4.springmvc支持,web导出可以简单明了使用1.easypoi...
- 关于Oracle数据库12c 新特性总结_oracle数据库12514
-
概述今天主要简单介绍一下Oracle12c的一些新特性,仅供参考。参考:http://docs.oracle.com/database/121/NEWFT/chapter12102.htm#NEWFT...
- 【开发者成长】JAVA 线上故障排查完整套路!
-
线上故障主要会包括CPU、磁盘、内存以及网络问题,而大多数故障可能会包含不止一个层面的问题,所以进行排查时候尽量四个方面依次排查一遍。同时例如jstack、jmap等工具也是不囿于一个方面的问题...
- 使用 Python 向多个地址发送电子邮件
-
在本文中,我们将演示如何使用Python编程语言向使用不同电子邮件地址的不同收件人发送电子邮件。具体来说,我们将向许多不同的人发送电子邮件。使用Python向多个地址发送电子邮件Python...
- 提高工作效率的--Linux常用命令,能够决解95%以上的问题
-
点击上方关注,第一时间接受干货转发,点赞,收藏,不如一次关注评论区第一条注意查看回复:Linux命令获取linux常用命令大全pdf+Linux命令行大全pdf为什么要学习Linux命令?1、因为Li...
- linux常用系统命令_linux操作系统常用命令
-
系统信息arch显示机器的处理器架构dmidecode-q显示硬件系统部件-(SMBIOS/DMI)hdparm-i/dev/hda罗列一个磁盘的架构特性hdparm-tT/dev/s...
- 小白入门必知必会-PostgreSQL-15.2源码编译安装
-
一PostgreSQL编译安装1.1下载源码包在PostgreSQL官方主页https://www.postgresql.org/ftp/source/下载区选择所需格式的源码包下载。cd/we...
- Linux操作系统之常用命令_linux系统常用命令详解
-
Linux操作系统一、常用命令1.系统(1)系统信息arch显示机器的处理器架构uname-m显示机器的处理器架构uname-r显示正在使用的内核版本dmidecode-q显示硬件系...
- linux网络命名空间简介_linux 网络相关命令
-
此篇会以例子的方式介绍下linux网络命名空间。此例中会创建两个networknamespace:nsa、nsb,一个网桥bridge0,nsa、nsb中添加网络设备veth,网络设备间...
- 一周热门
- 最近发表
-
- perl基础——循环控制_principle循环
- CHAPTER 2 The Antechamber of M de Treville 第二章 特雷维尔先生的前厅
- CHAPTER 5 The King'S Musketeers and the Cardinal'S Guards 第五章 国王的火枪手和红衣主教的卫士
- CHAPTER 3 The Audience 第三章 接见
- 别搞印象流!数据说明谁才是外线防守第一人!
- V-Day commemorations prove anti-China claims hollow
- EasyPoi使用_easypoi api
- 关于Oracle数据库12c 新特性总结_oracle数据库12514
- 【开发者成长】JAVA 线上故障排查完整套路!
- 使用 Python 向多个地址发送电子邮件
- 标签列表
-
- HTML 教程 (33)
- HTML 简介 (35)
- HTML 实例/测验 (32)
- HTML 测验 (32)
- JavaScript 和 HTML DOM 参考手册 (32)
- HTML 拓展阅读 (30)
- HTML文本框样式 (31)
- HTML滚动条样式 (34)
- HTML5 浏览器支持 (33)
- HTML5 新元素 (33)
- HTML5 WebSocket (30)
- HTML5 代码规范 (32)
- HTML5 标签 (717)
- HTML5 标签 (已废弃) (75)
- HTML5电子书 (32)
- HTML5开发工具 (34)
- HTML5小游戏源码 (34)
- HTML5模板下载 (30)
- HTTP 状态消息 (33)
- HTTP 方法:GET 对比 POST (33)
- 键盘快捷键 (35)
- 标签 (226)
- HTML button formtarget 属性 (30)
- opacity 属性 (32)
- transition 属性 (33)