从字符串使用看Golang和Rust对内存使用的区别

server/2025/1/16 4:31:38/

从字符串使用看Golang和Rust对内存使用的区别

​ 今天从Rust偶然回到Golang的世界,怎么写代码怎么别扭,总是忍不住在句子结尾加个分号…看到golang的字符串使用起来特别爽可以到处复制疯狂乱用,有一种从部队宿舍豆腐块被子的生活回归到居家肥宅的随意感,想起好久之前看的golang底层有关的内容,就写点东西来比较一下golangrust对string的使用。

Go的字符串

在 Go 中,每个字符串本质上是一个结构体,其定义好了就不可用索引进行修改,包含两个字段:

  1. 指向字符串内容的指针*byte):8 字节(在64 位架构下)。
  2. 字符串的长度len):8 字节。

其内存布局是这个这样的结构体:

golang">struct string {data uintptr // 指向字符串内容的指针len  int     // 字符串的长度
}

所以golang里面的一个string事实上占用的正真大小为:

golang">package mainimport ("fmt""unsafe"
)func main() {str := "hello"fmt.Printf("len(): %d bytes (content size)\n", len(str))fmt.Printf("Sizeof string struct: %d bytes\n", unsafe.Sizeof(str))fmt.Printf("Total estimated memory: %d bytes\n", unsafe.Sizeof(str)+uintptr(len(str)))
}

output:

String: hello
len(): 5 bytes (content size)
Sizeof string struct: 16 bytes
Total estimated memory: 21 bytes

Rust的字符串

String

rust里面有两种常用的字符串,一个是String,另一个是&str。

在Rust中,String是一个可变的、堆分配的类型,底层实现是一个Vec<u8>

rust">pub struct String {vec: Vec<u8>,
}

所以一个String本质上还包含着vector的结构,也就是:

  1. 指向堆分配数据的指针:8 字节(在64 位系统上)。
  2. 字符串的长度usize):8 字节。
  3. 堆分配容量usize):8 字节。

所以说一个rust的string所占用的内存就至少是24字节,而且其本质由于就是一个vector,可以根据索引修改vector里面的值

rust">fn main() {let s = String::from("hello");println!("Size of String struct: {} bytes", std::mem::size_of::<String>());println!("Content length: {} bytes", s.len());
}

output:

Size of String struct: 24 bytes
Content length: 5 bytes

&str

​ 另一个是&str,在Rust中,&str是一个字符串切片类型,它是对字符串数据的不可变引用。相比于String&str更轻量级,因为它只是一个指向实际字符串数据的引用,而不是负责管理字符串数据本身。简单来说&str就是一个对静态内存或者堆内存的一个引用。一个&str的大小是固定的,包含两个部分:

  1. 指向字符串内容的指针*const u8):8 字节(在 64 位系统上)。
  2. 字符串的长度usize):8 字节。

所以一个&str至少就是16字节。

rust">fn main() {let s = "hello"; // &str 类型println!("Size of &str: {} bytes", std::mem::size_of_val(&s));println!("Content length: {} bytes", s.len());
}

output:

Size of &str: 16 bytes
Content length: 5 bytes

why

&strString的关系

  1. String转换为&str

    • &str是对String数据的不可变引用。

    • 通过&操作可以将String转换为&str,这并不是简单的取地址,而是生成一个指向String内部数据的引用。

    • 示例:

      let s = String::from("hello");
      let slice: &str = &s; //将 String 转为&str
      println!("{}", slice);
      
  2. &str转换为String

    • 如果你需要一个拥有所有权的字符串,可以通过.to_string()String::from()&str转换为String

    • 示例:

      let slice: &str = "hello";
      let s: String = slice.to_string(); // 将 &str 转为 String
      println!("{}", s);
      

怎么要两个字符串?

都有String了,为什么还要个这种&str,有时候看别人的代码都只创建&str而不是String,这是为什么呢?而且String还可以修改可以直接克隆。

  1. 轻量级和高效
  • 内存开销更小

    • &str是不可变的引用,不需要额外的堆分配。
    • 它只包含一个指针和一个长度,总大小为16 字节,比String24 字节更小。
  • 数据共享

    • &str是对现有字符串数据的引用,不会创建新数据或重新分配内存。适用于只读场景,避免不必要的性能开销。
    • 例如,字符串字面量("hello")是静态分配的,用&str表示效率更高。
  • 性能优越

    • 在函数参数中使用&str而不是String,避免堆分配和拷贝。

    • 示例:

      rust">fn greet(name: &str) {println!("Hello, {}!", name);
      }
      let name = String::from("Alice");
      greet(&name); // 传递不可变引用,避免拷贝,类似于golang里面传递&string
      
  1. 安全性
  • &str的不可变性提供了额外的安全保障,确保引用的数据不会意外被修改。

3.适配静态字符串

  • 如果数据是静态的(如程序中的字符串字面量),选择&str是合适的,经常作为全局静态变量使用

    let s: &str = "hello world"; // 静态字符串
    

结尾

总结对比

特性RustString&strGolangstring
大小24字节16字节16字节
内存管理动态分配堆内存引用已有数据堆分配
是否可变可变不可变不可变
用途动态字符串管理,修改内容高效只读,数据共享很多
典型场景动态构建和管理字符串静态字符串,函数参数,全局变量很多

http://www.ppmy.cn/server/158730.html

相关文章

集中式架构vs分布式架构

一、集中式架构 如何准确理解集中式架构 1. 集中式架构的定义 集中式架构是一种将系统的所有计算、存储、数据处理和控制逻辑集中在一个或少数几个节点上运行的架构模式。这些中央节点&#xff08;服务器或主机&#xff09;作为系统的核心&#xff0c;负责处理所有用户请求和…

nginx增加新模块

一、动态增加第三方模块(不需要停止nginx进程就可以增加新模块。只需要reload) NGINX 从1.9.11开始增加动态模块支持&#xff0c;从此不再需要替换nginx文件即可增加第三方扩展。目前官方只有9个模块支持动态加载&#xff0c;其它的第三方模块还是需要使用传统方式安装。 这九…

探索图像编辑的无限可能——Adobe Photoshop全解析

文章目录 前言一、PS的历史二、PS的应用场景三、PS的功能及工具用法四、图层的概念五、调整与滤镜六、创建蒙版七、绘制形状与路径八、实战练习结语 前言 在当今数字化的世界里&#xff0c;视觉内容无处不在&#xff0c;而创建和编辑这些内容的能力已经成为许多行业的核心技能…

SpringCloud:gateway分发服务报302,Network Error

springcloud使用gateway分发服务&#xff0c;访问接口时一直报错&#xff1a; 多次试验后发现是pom.xml文件中引入的security依赖的问题&#xff0c;注释后重新启动&#xff0c;可以正常访问。 <!-- spring security 安全认证 --> <dependency><groupId>org…

GPU算力平台|在GPU算力平台部署Linly-Talker 数字人对话应用教程

文章目录 一、平台介绍GPU算力平台概述 二、人工智能研发为什么选择GPU算力平台GPU算力平台的独特魅力账号注册流程Linly-Talker 数字人对话的部署 一、平台介绍 GPU算力平台概述 GPU算力平台就像是一个专门为GPU加速计算打造的云端“超级加油站”&#xff0c;属于软件和信息…

git merge 压缩提交

在 Git 中&#xff0c;执行 git merge 时可以通过一些操作来“压缩”提交&#xff0c;通常是指将合并过程中的多个提交压缩成一个单一的提交。这可以通过使用 --squash 选项来完成&#xff0c;或者在合并后进行交互式 rebase。以下是两种常见的方法&#xff1a; 方法 1&#x…

如何用 SSH 访问 QNX 虚拟机

QNX 虚拟机默认是开启 SSH 服务的&#xff0c;如果要用 SSH 访问 QNX 虚拟机&#xff0c;就需要知道虚拟机的 IP 地址&#xff0c;用户和密码。本文我们来看看如何获取这些参数。 1. 启动虚拟机 启动过程很慢&#xff0c;请耐心等待。 2. 查看 IP 地址 等待 IDE 连接到虚拟机。…

计算机网络 (36)TCP可靠传输的实现

前言 TCP&#xff08;传输控制协议&#xff09;是一种面向连接的、可靠的、基于字节流的传输层通信协议。TCP通过多种机制实现可靠传输&#xff0c;这些机制主要包括连接管理、序列号和确认应答机制、重传机制、流量控制、拥塞控制等。 一、连接管理 TCP使用三次握手&#xff0…