Move语言 所有权
Move VM 实现了类似 Rust 的所有权功能。
每个变量只有一个所有者作用域。当所有者作用域结束时,变量将被删除。
变量的寿命与它的作用域一样长,我们曾经在表达式一章中看到过这种行为,大家还有没有印象?现在是了解其内部机制的绝佳时机了。
所有者是拥有某变量的作用域。变量可以在作用域内定义(例如,在脚本中使用关键字 let),也可以作为参数传递给作用域。由于 Move 中唯一的作用域是函数的作用域,所以除了这两种方法,没有其它方法可以将变量放入作用域。
每个变量只有一个所有者,这意味着当把变量作为参数传递给函数时,该函数将成为新所有者,并且第一个函数不再拥有该变量。或者可以说,第二个函数接管了变量的所有权。
script { use {{sender}}::M; fun main() { // Module::T is a struct let a : Module::T = Module::create(10); // here variable `a` leaves scope of `main` function // and is being put into new scope of `M::value` function M::value(a); // variable a no longer exists in this scope // this code won't compile M::value(a); } }
让我们看一下将变量传递给 value() 函数时,Move 内部发生的情况:
module M { // create_fun skipped struct T { value: u8 } public fun create(value: u8): T { T { value } } // variable t of type M::T passed // `value()` function takes ownership public fun value(t: T): u8 { // we can use t as variable t.value } // function scope ends, t dropped, only u8 result returned // t no longer exists }
我们可以看到,当函数 value() 结束时,t 将不复存在,返回的只是一个 u8 类型的值。如何让t仍然可用呢?当然,一种快速的解决方案是返回一个元组,该元组包含原始变量和其它结果,但是 Move 还有一个更好的解决方案。
move 和 copy
首先,我们了解一下 Move VM 的工作原理,以及将值传递给函数时会发生什么。Move VM 里有两个字节码指令:MoveLoc 和 CopyLoc,反映到 Move 语言层面,它们分别对应关键字move
和copy
。
将变量传递到另一个函数时,MoveLoc 指令被使用,它会被 move。我们可以像下面这样显式使用 move 关键字:
script { use {{sender}}::M; fun main() { let a : Module::T = Module::create(10); M::value(move a); // variable a is moved // local a is dropped } }
这段代码是没有问题的,但是我们平常并不需要显示使用 move,缺省 a 会被 move。那么 copy 又是怎么回事呢?
关键字 copy
如果想保留变量的值,同时仅将值的副本传递给某函数,则可以使用关键字 copy
。
script { use {{sender}}::M; fun main() { let a : Module::T = Module::create(10); // we use keyword copy to clone structure // can be used as `let a_copy = copy a` M::value(copy a); M::value(a); // won't fail, a is still here } }
上例中,我们第一次调用函数 value() 时,将变量 a 的副本传递给函数,并保留 a 在本地作用域中,以便第二次调用函数时再次使用它。
使用 copy 后,我们实际上复制了变量值从而增加了程序占用内存的大小。但是如果复制数据数据量比较大,它的内存消耗可能会很高。这里要注意了,在区块链中,交易执行时占用的内存资源是消耗交易费的,每个字节都会影响交易执行费用。因此不加限制的使用 copy 会浪费很多交易费。
现在,是时候学习引用
了,它可以帮助我们避免不必要的copy
从而节省一些费用。
许多编程语言都支持引用。引用是指向变量(通常是内存中的某个片段)的链接,你可以将其传递到程序的其他部分,而无需移动变量值。引用(标记为&)使我们可以使用值而无需拥有所有权。我们修改一下上面的示例,看看如何使用引用。mod ...