Mojo值的生命周期(Life of a value)详解
到目前为止,我们已经解释了 Mojo 如何允许您使用 Mojo 的所有权模型构建内存安全的高性能代码而无需手动管理内存。但是,Mojo 是为 系统编程而设计的,这通常需要对自定义数据类型进行手动内存管理。因此,Mojo 允许您根据需要执行此操作。需要明确的是,Mojo 没有引用计数器和垃圾收集器。
Mojo 也没有具有特殊权限的内置数据类型。标准库中的所有数据类型(例如Bool、 Int和 String)都以 结构体形式实现。您实际上可以使用MLIR 方言提供的低级原语编写自己的这些类型的替代品 。
Mojo 语言的优点在于它为您提供了这些用于系统编程的低级工具,但在一个框架内,可以帮助您构建安全且易于从高级程序使用的东西。也就是说,您可以深入底层并编写您想要的所有“不安全”代码,但只要您按照 Mojo 的值语义进行操作,实例化您的类型/对象的程序员根本不需要考虑内存管理,而且由于值所有权,行为将是安全且可预测的。
总之,类型作者有责任管理每个值类型的内存和资源,方法是根据需要实现特定的生命周期方法,例如构造函数、复制构造函数、移动构造函数和析构函数。Mojo 默认不创建任何构造函数,但它确实为未定义自己的类型添加了一个简单的无操作析构函数。
接下来,我们将准确解释如何根据值语义定义这些生命周期方法,以便您的类型能够很好地与值所有权兼容。
生命周期和寿命(Lifecycles and lifetimes)
首先,让我们澄清一些术语:
- 值的“生命周期”由结构中的各种dunder方法定义。每个生命周期事件都由不同的方法处理,例如构造函数(__init__())、析构函数(__del__()。所有使用相同类型声明的值都具有相同的生命周期。
- 值的“生命周期”由程序执行期间每个值被视为有效的时间跨度定义。值的生命周期从初始化时开始,到销毁时结束,通常(但并非总是)从__init__()到__del__()。没有两个值具有完全相同的生命周期,因为每个值都是在不同的时间点创建和销毁的(即使差异是不可感知的)。
Mojo 中值的生命周期始于变量初始化时,一直持续到最后一次使用该值,此时 Mojo 会将其销毁。Mojo 会在不再使用每个值/对象时立即销毁它,使用在每个子表达式之后运行的“尽快”(ASAP) 销毁策略。
您可能可以想象,如果在程序的生命周期中,某个值在多个函数之间多次共享,那么跟踪该值的生命周期可能会很困难。但是,Mojo 通过其值语义和值所有权部分地使这一点变得可预测。生命周期管理的最后一块拼图是值的生命周期:每个值(在结构中定义)都需要实现关键的生命周期方法,这些方法定义了如何创建和销毁值。
值的生命周期(Life of a value)
Mojo 中值的生命周期始于变量初始化时,一直持续到最后一次使用该值,此时 Mojo 会将其销毁。
Mojo 中的所有数据类型(包括标准库中的基本类型,例如 Bool、 Int和 String,以及复杂类型,例如SIMD和 object)都定义为 struct。这意味着任何数据的创建和销毁都遵循相同的生命周期规则,并且您可以定义自己的数据类型,其工作方式完全相同。
Mojo 结构没有任何默认的生命周期方法,例如构造函数、复制构造函数或移动构造函数。这意味着您可以在没有构造函数的情况下创建结构,但您无法实例化它,并且它只能用作静态方法的一种命名空间。例如:
struct NoInstances:var state: Int@staticmethodfn print_hello():print("Hello world!")
如果没有构造函数,则无法实例化 this,因此它没有生命周期。该 state字段也是无用的,因为它无法初始化(Mojo 结构不支持默认字段值 - 只有必须在构造函数中初始化它们)。
NoInstances.print_hello()
输出:
Hello world!
以下代码无法通过编译。
print(NoInstances.state) #cannot access instance field 'state' without an instance of 'NoInstances'
构造函数
要创建 Mojo 类型的实例,需要__init__()构造函数方法。构造函数的主要职责是初始化所有字段。例如:
struct MyPet:var name: Stringvar age: Intfn __init__(inout self, name: String, age: Int):self.name = nameself.age = age
现在我们可以创建一个实例:
var mine = MyPet("Loki", 4)
的实例MyPet也可以被 borrowed 和 destroyed,但目前不能被复制或移动。
我们认为这是一个很好的默认起点,因为没有内置的生命周期事件,也没有意外行为。您(类型作者)必须通过实现复制和移动构造函数来明确决定是否可以复制或移动类型以及如何复制或移动类型。
Mojo 不需要析构函数来销毁对象。只要结构中的所有字段都是可销毁的(标准库中的每个类型都是可销毁的, 指针除外),那么 Mojo 就知道如何在其生命周期结束时销毁该类型。我们将在值的消亡中进一步讨论这一点。
重载构造函数
与其他函数/方法一样,您可以 重载构造函数 __init__()以使用不同的参数初始化对象。例如,您可能需要一个默认构造函数来设置一些默认值并且不接受任何参数,然后需要接受更多参数的附加构造函数。
请注意,为了修改任何字段,每个构造函数都必须使用inout约定声明self参数。如果要从另一个构造函数调用一个构造函数,只需像在外部调用一样调用该构造函数(无需传递self)
例如,下面是如何从重载构造函数委托工作的方法:
struct MyPet:var name: Stringvar age: Intfn __init__(inout self):self.name = ""self.age = 0fn __init__(inout self, name: String):self = MyPet()self.name = name
字段初始化
请注意,在上例中,每个构造函数结束时,所有字段都必须初始化。这是构造函数中唯一的要求。
事实上,只要所有字段都已初始化,__init__()构造函数就足够聪明,甚至在构造函数完成之前就将self对象视为已完全初始化。例如,一旦所有字段都初始化,此构造函数就可以传递self:
fn use(arg: MyPet):passstruct MyPet:var name: Stringvar age: Intfn __init__(inout self, name: String, age: Int, cond: Bool):self.name = nameif cond:self.age = ageuse(self) # Safe to use immediately!self.age = ageuse(self) # Safe to use immediately!
下面的初始化会报错
struct MyPet:var name: Stringvar age: Intfn __init__(inout self, name相关文章:
Mojo值的生命周期(Life of a value)详解
到目前为止,我们已经解释了 Mojo 如何允许您使用 Mojo 的所有权模型构建内存安全的高性能代码而无需手动管理内存。但是,Mojo 是为 系统编程而设计的,这通常需要对自定义数据类型进行手动内存管理。因此,Mojo 允许您根据需要执行此操作。需要明确的是,Mojo 没有引用计数器…...
java对接kimi详细说明,附完整项目
需求: 使用java封装kimi接口为http接口,并把调用kimi时的传参和返回数据,保存到mysql数据库中 自己记录一下,以做备忘。 具体步骤如下: 1.申请apiKey 访问:Moonshot AI - 开放平台使用手机号手机号验证…...
鸿蒙媒体开发【基于AVCodec能力的视频编解码】音频和视频
基于AVCodec能力的视频编解码 介绍 本实例基于AVCodec能力,提供基于视频编解码的视频播放和录制的功能。 视频播放的主要流程是将视频文件通过解封装->解码->送显/播放。视频录制的主要流程是相机采集->编码->封装成mp4文件。 播放支持的原子能力规…...
django集成pytest进行自动化单元测试实战
文章目录 一、引入pytest相关的包二、配置pytest1、将django的配置区分测试环境、开发环境和生产环境2、配置pytest 三、编写测试用例1、业务测试2、接口测试 四、进行测试 在Django项目中集成Pytest进行单元测试可以提高测试的灵活性和效率,相比于Django自带的测试…...
48天笔试训练错题——day40
目录 选择题 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 编程题 1. 发邮件 2. 最长上升子序列 选择题 1. DNS 劫持又称域名劫持,是指在劫持的网络范围内拦截域名解析的请求,分析请求的域名,把审查范围以外的请求放行,否则返回…...
LabVIEW在DCS中的优势
DCS(Distributed Control System,分布式控制系统)是一种用于工业过程控制的自动化系统。它将控制任务分散到多个控制单元中,通过网络连接和协调这些单元来实现对整个过程的监控和控制。DCS通常用于大型工业设施,如化工…...
英特尔:从硅谷创业到全球科技巨头
在科技行业,英特尔不仅是一个品牌,更是一种精神的象征。自1968年成立以来,英特尔经历了从初创企业到全球半导体产业领导者的华丽转变,其发展历程是科技创新与市场战略完美结合的典范。本文将深入探讨英特尔的发展历程,…...
生物计算与纳米技术:交汇前沿的科学领域
在当今科技迅猛发展的时代,生物计算和纳米技术作为前沿科技领域的两个重要方向,正在逐渐融合并带来深远的影响。生物计算涉及使用生物系统进行计算和数据存储,而纳米技术则关注制造极小尺度的电子器件和材料科学。本文将深入探讨这两个领域的…...
C#中栈和队列
在C#中,Stack和Queue是两种不同的集合类型,它们用于实现后进先出(LIFO)和先进先出(FIFO)的数据结构。 Stack(堆栈) Stack是一个后进先出的集合,这意味着最后一个添加到堆…...
技战法丨攻防演练防御——纵深、联动、诱捕(可搬运、可cv)
演习活动经过近几年的发展,攻击方的专业水平已大幅提高,逐渐呈现出隐秘化、APT化的趋势。其利用渗透技术对目标系统做深入探测,不断挖掘防守方网络系统的薄弱环节,这就要求防守方构建立体式纵深防护体系来抵御入侵。同时ÿ…...
1、 window平台opencv下载编译, 基于cmake和QT工具链
1. 环境准备,源码下载 1.1 前置环境 qt 下载安装cmake 安装,可参考: https://blog.csdn.net/qq_51355375/article/details/139186681 1.2 opencv 源码下载 官网地址: https://opencv.org/releases/ 下载源码: 2 …...
C++20三向比较运算符详解
三向比较运算符可以用于确定两个值的大小顺序,也被称为太空飞船操作符。使用单个表达式,它可以告诉一个值是否等于,小于或大于另一个值。 它返回的是类枚举(enumeration-like)类型,定义在 <compare> …...
监听机制与耗电量
一、监听机制与耗电量的关系 监听机制通常涉及对特定事件、状态或数据的持续监测。在移动设备和嵌入式系统中,这种监听可能由多种组件和传感器实现,如GPS、传感器(如加速度计、陀螺仪)、网络连接等。监听的频率越高,意…...
C++ //练习 16.29 修改你的Blob类,用你自己的shared_ptr代替标准库中的版本。
C Primer(第5版) 练习 16.29 练习 16.29 修改你的Blob类,用你自己的shared_ptr代替标准库中的版本。 环境:Linux Ubuntu(云服务器) 工具:vim 代码块 template <typename> class BlobP…...
【Mode Management】CanNm处于PBS状态下接收到一帧诊断报文DCM会响应吗
目录 前言 正文 1.CanNm从RSS状态切换到PBS状态行为分析 1.1.CanNm动作 1.2.ComM动作 1.3.DCM动作 1.4 小结 2.CanNM在PBS状态下收到一帧诊断报文行为分析 2.1.DCM动作1 2.2. ComM动作 2.3. DCM动作2 2.3. CanNm动作 2.4 问题 2.5 分析 3.总结 前言 我们知道EC…...
【C++】模版:范式编程、函数模板、类模板
目录 一.范式编程 二.函数模板 1.概念与格式 2.原理 3.实例化 4.匹配规则 三.类模板 一.范式编程 在写C函数重载的时候,可能会写很多同一类的函数,例如交换函数: void Swap(int& left, int& right) {int temp left;left r…...
验证图片旋转
最近在使用百度图片翻译时遇到一个问题,就是图片会翻转90,经与百度沟通,发现是原始图片中有个旋转参数引起的。 于是写个demo验证一下。 // 获取元数据中的旋转方向 func getOrientation() int {//打开图像文件f, err : os.Open("image…...
宏景eHR /ajax/ajaxService SQL注入漏洞复现
0x01 产品简介 宏景eHR人力资源管理软件是一款人力资源管理与数字化应用相融合,满足动态化、协同化、流程化、战略化需求的软件。 0x02 漏洞概述 宏景eHR /ajax/ajaxService 接口处存在SQL注入漏洞,,未经身份验证的远程攻击者通过利用SQL注入漏洞配合数据库xp_cmdshell可…...
从源码看 Redis:深入理解 redisDb 和 redisObject
Redis 是一个广泛使用的内存数据库,以其高性能和丰富的数据结构而闻名。不同于磁盘数据库,磁盘数据库将数据读取到文件中维护,而内存数据库将数据存储在内存中,意味着其想要维护数据,必须在代码中维护一个保存数据的结…...
unity中实现流光效果——世界空间下
Properties{_MainTex ("Texture", 2D) "white" {}_FlowColor ("Flow Color", Color) (1, 1, 1, 1) // 流光颜色_FlowFrequency ("Flow Frequency", Float) 1.0 // 流光频率_FlowSpeed ("Flow Speed", Float) 1.0 // 流光…...
TDengine 快速体验(Docker 镜像方式)
简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能,本节首先介绍如何通过 Docker 快速体验 TDengine,然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker,请使用 安装包的方式快…...
Unity3D中Gfx.WaitForPresent优化方案
前言 在Unity中,Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染(即CPU被阻塞),这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案: 对惹,这里有一个游戏开发交流小组&…...
代理篇12|深入理解 Vite中的Proxy接口代理配置
在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...
深入浅出深度学习基础:从感知机到全连接神经网络的核心原理与应用
文章目录 前言一、感知机 (Perceptron)1.1 基础介绍1.1.1 感知机是什么?1.1.2 感知机的工作原理 1.2 感知机的简单应用:基本逻辑门1.2.1 逻辑与 (Logic AND)1.2.2 逻辑或 (Logic OR)1.2.3 逻辑与非 (Logic NAND) 1.3 感知机的实现1.3.1 简单实现 (基于阈…...
push [特殊字符] present
push 🆚 present 前言present和dismiss特点代码演示 push和pop特点代码演示 前言 在 iOS 开发中,push 和 present 是两种不同的视图控制器切换方式,它们有着显著的区别。 present和dismiss 特点 在当前控制器上方新建视图层级需要手动调用…...
【Linux】自动化构建-Make/Makefile
前言 上文我们讲到了Linux中的编译器gcc/g 【Linux】编译器gcc/g及其库的详细介绍-CSDN博客 本来我们将一个对于编译来说很重要的工具:make/makfile 1.背景 在一个工程中源文件不计其数,其按类型、功能、模块分别放在若干个目录中,mak…...
HybridVLA——让单一LLM同时具备扩散和自回归动作预测能力:训练时既扩散也回归,但推理时则扩散
前言 如上一篇文章《dexcap升级版之DexWild》中的前言部分所说,在叠衣服的过程中,我会带着团队对比各种模型、方法、策略,毕竟针对各个场景始终寻找更优的解决方案,是我个人和我司「七月在线」的职责之一 且个人认为,…...
用鸿蒙HarmonyOS5实现中国象棋小游戏的过程
下面是一个基于鸿蒙OS (HarmonyOS) 的中国象棋小游戏的实现代码。这个实现使用Java语言和鸿蒙的Ability框架。 1. 项目结构 /src/main/java/com/example/chinesechess/├── MainAbilitySlice.java // 主界面逻辑├── ChessView.java // 游戏视图和逻辑├──…...
【UE5 C++】通过文件对话框获取选择文件的路径
目录 效果 步骤 源码 效果 步骤 1. 在“xxx.Build.cs”中添加需要使用的模块 ,这里主要使用“DesktopPlatform”模块 2. 添加后闭UE编辑器,右键点击 .uproject 文件,选择 "Generate Visual Studio project files",重…...
MySQL体系架构解析(三):MySQL目录与启动配置全解析
MySQL中的目录和文件 bin目录 在 MySQL 的安装目录下有一个特别重要的 bin 目录,这个目录下存放着许多可执行文件。与其他系统的可执行文件类似,这些可执行文件都是与服务器和客户端程序相关的。 启动MySQL服务器程序 在 UNIX 系统中,用…...
