Rust 中 unsafe 关键字的语义

之前我都没注意到,不同的场景下 unsafe 关键字的语义可能有很大不同(可能随着我的理解深入,能把这些语义统一起来吧)。本文主要介绍在三个不同场景下 unsafe 的语义。

unsafe block

unsafe block 里的 unsafe 是强制性的,是用于"提权"的。rust 代码中有些操作不用 unsafe block 提权是不能通过编译的,比如:

  • deref raw ptr
  • 调 FFI
  • inline asm
  • 调 unsafe fn

所以这里的 unsafe 的语义是"提权",是编译器强制要求开发者添加的。

unsafe fn

这里的 unsafe 是规范性的,用于提醒函数的调用者,需要满足特定的条件才能调用此函数。

unsafe fn 里的 unsafe 并不能提权,也就是函数实现里如果想进行 unsafe 的操作,还需要再使用 unsafe block(可能旧版本的 rust 并不需要,这一点有待验证)。反过来,函数内使用 unsafe block,不代表函数一定是 unsafe fn 的。所以说这里的 unsafe 是规范性的,是开发者为了保证代码质量自觉标明的。

unsafe trait

这里的 unsafe 也是规范性的,用于提醒 trait 的实现者,在编写 impl trait 时要注意满足特定的语义。以典型的 unsafe trait Sync 为例,开发者都相信,实现了 Sync 的类型,其引用可以在线程间传递。如果有人在实现 Sync 时,没有保证目标类型的引用可以在线程间传递,就可能让人们在使用这个类型时发生 UB。

比较微妙的一点是,其实所有 trait 都要求实现者在实现时合理地实现每个接口,那 unsafe trait 有什么特殊之处呢?关键在于,unsafe trait 实现的语义要被 unsafe code 依赖,并且会影响 unsafe code 是否会发生 UB。

一般的 trait 所承载的语义,并不会影响使用这个 trait 的代码。比如,如果一个 trait 只被 safe code 调用,无论其内部实现为何,其绑定的语义为何,safe code 都不会发生 UB,因为 safe code 能做的事情有限,他调用一个胡乱实现的 trait,可能会出 bug,但不会出 UB。即使是 trait 的实现内部会发生 UB,也不会传递到 safe code 中,所以不算 safe code 发生 UB。

但如果一个 trait 会被 unsafe code 调用,并且 unsafe code 会基于这个 trait 的语义做一些事,那就可能因为 trait 的实现没有满足语义要求,而导致 unsafe code 中发生 UB。对于这种 trait,就应该规范地将其标为 unsafe trait。

相关推荐
mmsx11 分钟前
Android Dialog 插槽模式:用一套壳统一全应用的弹窗风格
android·java·dialog·开发语言
huanbailu16 分钟前
Qt 跨线程信号槽:connect 返回 true 但槽函数不执行的坑
开发语言·c++·qt·信号槽·跨线程·元类型
ZealSinger23 分钟前
Go slog生产落地LevelVar与共存
开发语言·后端·golang·go
落魄实习生32 分钟前
Agent Scope Java 2.x 系列【11】AgentState 与状态存储
java·开发语言·ai
HEJOO932 分钟前
C++ 虚函数表(vtable)深度解析
开发语言·c++
老王爱玩车35 分钟前
深入理解指针5
c语言·开发语言·学习
丹宇码农1 小时前
Go 与 Python 协程(Coroutine)对比演示项目
开发语言·python·golang
ttwuai1 小时前
Go开源后台管理系统推荐:3个官方仓库怎么按技术栈和适用边界比较?
开发语言·golang·开源
个 人 练 习 生2 小时前
C++-----string基本使用详解
开发语言·c++·学习
朝朝辞暮i2 小时前
C++ 第 5 课:else if + 多条件判断 + && / || / !
开发语言·c++