阅读量:0
使用某些编程语言时,您可能会面临的挑战是必须手动分配和释放内存。当程序的多个部分需要访问同一内存时,很难跟踪谁“拥有”某个值并确定何时是释放它的正确时间。如果您犯了一个错误,可能会导致“释放后使用”错误、“双重释放”错误或“内存泄漏”错误,其中任何一个都可能是灾难性的。
Mojo 可确保每次只有一个变量拥有每个值,从而避免这些错误,同时仍允许您与其他函数共享引用。当所有者的生命周期结束时,Mojo会销毁该值。
在本节,我们将解释管理此所有权模型的规则以及如何指定定义如何将值共享到函数中的不同参数约定。
论点惯例
在所有编程语言中,代码质量和性能在很大程度上取决于函数如何处理参数值。也就是说,函数接收的值是唯一值还是引用,以及它是可变的还是不可变的,会产生一系列影响,这些影响决定了语言的可读性、性能和安全性。
在 Mojo 中,我们希望默认提供完整的值语义,从而提供一致且可预测的行为。但作为系统编程语言,我们还需要提供对内存优化的完全控制,这通常需要引用语义。诀窍是引入引用语义,通过跟踪每个值的生命周期并在正确的时间(并且只一次)销毁每个值,从而确保所有代码都是内存安全的。所有这些都是通过使用参数约定在 Mojo 中实现的,这些约定确保每个值一次只有一个所有者。
参数约定指定参数是可变的还是不可变的,以及函数是否拥有该值。每个约定都由参数声明开头的关键字定义:
- borrowed:函数接收一个不可变引用。这意味着函数可以读取原始值(它不是副本),但不能改变(修改)它。def函数对此有不同的处理,如下所述。
- inout:函数接收一个可变引用。这意味着函数可以读取和改变原始值(它不是副本)。
- owned:函数取得所有权。这意味着函数对参数具有独占可变访问权限 — 函数调用者不再有权访问此值。通常,这也意味着调用者应将所有权转让给此函数,但情况并非总是如此,这可能是一个副本(正如您将在下面了解到的那样)。
例如,此函数有一个可变引用参数和一个不可变引用参数:
fn add(inout x: Int, borrowed y: Int): x += y fn main(): var a = 1 var b = 2 add(a, b) print(a) print(b)
输出:
3 2
您可能已经看到过一些没有声明约定的函数参数。默认情况下,所有参数都是borrowed。但是def和fn 函数对待borrowed参数的方式略有不同:
- 在fn函数中,函数总是接收一个不可变的引用。如果你想要一个可变的副本,你可以将其分配给局部变量:
var my_copy = borrowed_arg
- 在def函数中,如果函数改变值,函数将收到参数的可变副本。否则,它将收到不可变引用。这允许您将参数视为可变的,但避免在不需要时制作额外副本的开销。
函数中borrowed和之间的区别可能有点微妙:owneddef
- 在def函数中,borrowed参数作为不可变