赞
踩
一旦不再使用某个值/对象,Mojo 就会将其销毁。Mojo 不会等到 代码块结束(甚至不会等到表达式结束)才销毁未使用的值。它使用在每个子表达式之后运行的“尽快”(ASAP)销毁策略来销毁值。即使在像这样的表达式中a+b+c+d,Mojo 也会在不再需要中间值时立即销毁它们。
Mojo 使用静态编译器分析来查找值最后一次使用的位置。然后,Mojo 立即结束该值的生命周期并调用析__del__() 构函数来执行该类型的任何必要清理。
例如,请注意__del__()每个实例的析构函数被调用的时间MyPet:
@value struct MyPet: var name: String var age: Int fn __del__(owned self): print("Destruct", self.name) fn pets(): var a = MyPet("Loki", 4) var b = MyPet("Sylvie", 2) print(a.name) # a.__del__() runs here for "Loki" a = MyPet("Charlie", 8) # a.__del__() runs immediately because "Charlie" is never used print(b.name) # b.__del__() runs here pets()
输出为:
Loki
Destruct Loki
Destruct Charlie
Sylvie
Destruct Sylvie
请注意,每个值的初始化都与对析构函数的调用相匹配,并且a实际上会被销毁多次 - 每次收到新值时都会销毁一次。
大多数结构不需要自定义析构函数,如果你没有定义析构函数,Mojo 会自动添加一个无操作析构函数。
您可能想知道 Mojo 如何在没有自定义析构函数的情况下销毁类型,或者为什么无操作析构函数很有用。如果类型只是字段的集合(如示例)MyPet,则 Mojo 只需销毁字段:MyPet不会动态分配内存或使用任何长期存在的资源(如文件句柄)。当值被销毁时,对于MyPet的销毁无需采取任何特殊操作。
查看各个字段,MyPet包括一个Int和String。
Mojo的Int称其为简单类型。它是静态大小位数。Mojo 确切知道它有多大,因此可以重复使用这些位来存储其他内容。
Mojo的String值稍微复杂一些。Mojo 字符串是可变的。该 String对象有一个内部缓冲区 - 一个 List字段,它保存组成字符串的字符。AList将其内容存储在堆上动态分配的内存中,因此字符串可以增大或缩小。字符串本身没有任何特殊的析构函数逻辑,但当 Mojo 销毁字符串时,它会调用该字段的析构函数 List,从而取消分配内存。
由于String和Int不需要任何自定义析构函数逻辑,它们都具有无操作析构函数:字面意思是__del__()不执行任何操作的方法。这似乎毫无意义,但这意味着 Mojo 可以在任何值的生命周期结束时调用其析构函数。这使得编写通用容器和算法变得更加容易。
与其他语言类似,Mojo 遵循对象/值在构造函数(init())中获取资源并在析构函数(del())中释放资源的原则。但是,Mojo 的 ASAP 销毁比基于范围的销毁具有一些优势(例如 C++ RAII 模式,它等到代码范围结束后才销毁值):
此外,Mojo 的 ASAP 销毁在 Python 风格的def 函数中效果很好。这是因为 Python 实际上不提供超出函数范围的范围,因此 Python 垃圾收集器清理资源的频率比基于范围的销毁策略更高。但是,Mojo 不使用垃圾收集器,因此 ASAP 销毁策略提供的销毁保证比 Python 更细粒度。
Mojo 的销毁策略与 Rust 和 Swift 的工作方式更相似,因为它们都具有强大的值所有权跟踪功能并提供内存安全性。一个区别是 Rust 和 Swift 需要使用动态“删除标志” ——它们维护隐藏的影子变量来跟踪值的状态以提供安全性。这些通常会被优化掉,但 Mojo 方法完全消除了这种开销,
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。