地址(Address)
address
是 Move 语言的内置类型,用于表示全局存储中的位置(有时称为账户)。一个 address
值是一个 256 位(32 字节)的标识符。在给定地址下可以存储两种内容:模块和资源。
虽然 address
底层实现是 256 位整数,但 Move 地址被设计为不透明的——它们不能从整数创建,不支持算术运算,也不可修改。尽管某些场景可能需要这类特性(例如 C 语言中的指针算术就有类似用途),但 Move 出于支持静态验证的设计目标,不允许这种动态行为。
你可以在运行时使用地址值(address
类型)来访问该地址下的资源,但_无法_通过地址值在运行时访问模块。
地址及其语法
地址有两种形式:命名地址和数值地址。命名地址的语法遵循 Move 中命名标识符的通用规则。数值地址的语法不限于十六进制值,任何有效的 u256
数值都可以作为地址值,例如 42
、0xCAFE
和 2021
都是有效的数值地址字面量。
为区分地址是否在表达式上下文中使用,其语法会根据使用场景有所不同:
通常可以将 @
视为一个运算符,它将地址从命名空间项转换为表达式项。
命名地址
命名地址允许在任何使用地址的地方用标识符替代数值,而不仅限于值层面。命名地址在 Move 包中作为顶层元素(模块和脚本之外)声明和绑定,或作为参数传递给 Move 编译器。
命名地址仅存在于源代码层面,在字节码层面会被完全替换为其对应的数值。因此,模块和模块成员_必须_通过模块的命名地址访问,而不能通过编译时分配给命名地址的数值访问。例如,即使 Move 程序编译时将 my_addr
设为 0x2
,use my_addr::foo
也_不等同_于 use 0x2::foo
。这个区别在模块与脚本章节有更详细的讨论。
示例
script {
fun example() {
let a1: address = @0x1; // 0x0000000000000000000000000000000000000000000000000000000000000001 的简写
let a2: address = @0x42; // 0x0000000000000000000000000000000000000000000000000000000000000042 的简写
let a3: address = @0xDEADBEEF; // 0x00000000000000000000000000000000000000000000000000000000DEADBEEF 的简写
let a4: address = @0x000000000000000000000000000000000000000000000000000000000000000A;
let a5: address = @std; // 将命名地址 `std` 的值赋给 `a5`
let a6: address = @66;
let a7: address = @0x42;
}
}
module 66::some_module { // 非表达式上下文,无需 @ 前缀
use 0x1::other_module; // 非表达式上下文,无需 @ 前缀
use std::vector; // 引用其他模块时可将命名地址作为命名空间项使用
...
}
module std::other_module { // 声明模块时可将命名地址作为命名空间项使用
...
}
全局存储操作
address
值的主要用途是与全局存储操作进行交互。
address
值会与 exists
、borrow_global
、borrow_global_mut
和 move_from
操作 一起使用。
唯一 不 使用 address
的全局存储操作是 move_to
,该操作使用 signer
。
所有权
与语言中内置的其他标量值一样,address
值是隐式可复制的,这意味着它们无需显式指令(如 copy
)即可被复制。