仓颉编程语言青少年基础教程:enum(枚举)类型和Option类型

仓颉编程语言青少年基础教程:enum(枚举)类型和Option类型

enum 和 Option 各自解决一类“语义级”问题:

enum 让“取值只在有限集合内”的约束从注释变成编译器强制;

Option 让“值可能不存在”的语义显式化。

enum类型

enum 类型提供了通过列举一个类型的所有可能取值来定义此类型的方式。

定义 enum 时需要把它所有可能的取值一一列出,称这些值为 enum 的构造器(constructor)。

仓颉的枚举(enum)类型,简单说就是:通过把一个类型所有可能的 “选项” 列出来,来定义这个类型。

枚举只能定义在文件的最顶层(不能嵌套在函数或其他类型里)。

枚举的定义

基本语法:

enum <类型名> {

    | <构造器1> [参数]

    | <构造器2> [参数]

    ......

    | ... // 非穷举(non-exhaustive)构造器,只能有一个且在最后

}

说明:用enum关键字开头,后面跟类型名,大括号里列出所有可能的 “选项”(官方叫 “构造器”),选项之间用|隔开。

  •  构造器分无参(如 Red)和有参(如 Red(UInt8))

  •  支持同名构造器(需参数个数不同)

  •  可包含递归定义(构造器参数使用自身类型)

  •  可添加 ... 作为最后一个构造器(non-exhaustive enum,不可直接匹配)

注意,构造器(constructor)的含义,枚举的 “构造器” = 枚举类型的 “所有可能取值”,和类里的 “构造器(构造函数)” 不是一回事。

基本示例源码:

// 1. 顶层 enum 定义
enum RGBColor {| Red | Green                 // 无参构造器| Blue(UInt8)                 // 有参构造器(亮度值)// 成员函数:打印颜色信息public func describe(): Unit {      // ① 必须显式写出返回类型 Unitmatch (this) {                   // ② match 后面要加括号case Red => println("Red")case Green => println("Green")case Blue(brightness) => println("Blue with brightness: ${brightness}") // ③ 字符串插号语法}}
}// 2. 主函数入口
main(): Int64 {                        let red   = RGBColor.Red            // 全名访问,稳妥let green = RGBColor.Green          //  为避免歧义,统一加类型名let blue  = RGBColor.Blue(150)red.describe()    // 输出:Redgreen.describe()  // 输出:Greenblue.describe()   // 输出:Blue with brightness: 150return 0                        
}

编译运行截图:

使用(创建枚举的实例的)规则

  •  通过 类型名.构造器 或直接用构造器创建实例(无歧义时)

  •  名字冲突时必须加类型名(如与变量 / 函数同名)

例如:

let c1 = Color.Red  // 完整写法

let c2 = Red       // 简写,前提是不跟别的 Red 冲突

如果当前作用域里已经有一个变量叫 Red,那就必须写全名 Color.Red,否则编译器会以为你在用那个变量。

完整示例:

enum Color {| Red| Yellow| Green
}// 模拟变量名冲突
let Red = "字符串变量Red"func message(light: Color): String {match (light) {case Red    => "停!" case Yellow => "注意!"case Green  => "通行!"}
}main() {let light = Yellow     // 可以用 Yellow 或Color.Yellowprintln(message(light))             // 输出:注意!let light2 = Green   // 可以用 Green 或Color.Greenprintln(message(light2))             // 输出:通行!let light3 = Color.Red    // 只能用Color.Red ,不能用Redprintln(message(light3))             // 输出:停!  println(Red) //  输出:字符串变量Red
}

编译运行输出:

注意!
通行!       
停!
字符串变量Red

重要事项说明

1.构造器比较灵活:
(1)可以带参数(带附加信息)
比如想表示 “红色的亮度”,可以给Red加个参数(比如 0-255 的数值):
enum RGBColor {
| Red(UInt8) | Green(UInt8) | Blue(UInt8)
}
// 比如 Red(255) 就表示“亮度为255的红色”

(2)可以有同名选项,但参数个数必须不同
比如既可以有 “单纯的红色”(不带参数),也可以有 “带亮度的红色”(带参数):
plaintext
enum RGBColor {
| Red | Green | Blue  // 不带参数的选项
| Red(UInt8) | Green(UInt8) | Blue(UInt8)  // 带参数的同名选项(参数个数不同)
}

(3)可以有一个 “省略号选项”...
加在最后,表示 “还有其他没列出来的选项”(这种枚举叫 non-exhaustive enum)。用的时候不能直接匹配这个...,得用通配符_(比如 “其他所有情况”):
plaintext
enum T {
| Red | Green | Blue | ...  // 最后一个是省略号,表示还有其他可能
}

2.枚举可以 “自己包含自己”(递归定义)
枚举的选项参数可以是它自己的类型,这在定义复杂结构时很有用。
比如定义一个 “数学表达式” 类型:
•  可以是一个数字(Num)
•  可以是两个表达式相加(Add)
•  可以是两个表达式相减(Sub)
可以这样写:
enum Expr {
| Num(Int64)  // 数字,参数是具体数值(比如Num(5))
| Add(Expr, Expr)  // 加法,参数是两个表达式(比如Add(Num(2), Num(3))表示2+3)
| Sub(Expr, Expr)  // 减法,同理
}
这样你就能表达 1 + (2 - 3) 这样的嵌套结构。
完整示例源码如下:

// 定义递归枚举:表示数学表达式
enum Expr {| Num(Int64)          // 数字| Add(Expr, Expr)     // 加法| Sub(Expr, Expr)     // 减法
}// 定义一个递归函数:计算Expr表达式的值
func eval(expr: Expr): Int64 {match (expr) {case Num(n) => n  // 如果是数字,直接返回数值case Add(a, b) => eval(a) + eval(b) // 加法:递归计算左右两边再相加case Sub(a, b) => eval(a) - eval(b) // 减法:递归计算左右两边再相减}
}// 构造表达式:1 + (2 - 3)
let nestedExpr = Add(Num(1), // 左边:1Sub(Num(2), Num(3)) // 右边:2 - 3
)main(): Unit {let result = eval(nestedExpr)println(result)   // 输出:0,因为1 + (2-3) = 1 + (-1) = 0
}

3.枚举里可以加 “功能”(函数 / 属性)
可以在枚举里定义函数或属性,但名字不能和选项(构造器)重复。完整示例源码如下:

// 带亮度参数的RGB颜色枚举
enum RGBColor {| Red(UInt8)   // 红色(亮度0-255)| Green(UInt8) // 绿色| Blue(UInt8)  // 蓝色// 成员函数:打印颜色和亮度信息func printInfo() {// 使用this指代当前实例match (this) {case Red(b) => println("红色,亮度:${b}")case Green(b) => println("绿色,亮度:${b}")case Blue(b) => println("蓝色,亮度:${b}")}}// 成员函数:判断是否为高亮度(亮度>127)func checkHighBright(): Bool {match (this) {case Red(b) => return b > 127case Green(b) => return b > 127case Blue(b) => return b > 127}}
}// 程序入口(无需func修饰)
main() {let red = RGBColor.Red(200)let green = RGBColor.Green(50)// 调用枚举成员函数red.printInfo()          // 输出:红色,亮度:200println("红色是否高亮度:${red.checkHighBright()}")  // 输出:红色是否高亮度:truegreen.printInfo()        // 输出:绿色,亮度:50println("绿色是否高亮度:${green.checkHighBright()}")// 输出:绿色是否高亮度:false
}

输出:

红色,亮度:200
红色是否高亮度:true 
绿色,亮度:50       
绿色是否高亮度:false

Option类型

Option 是 enum 的泛型应用,专门处理 “可能为空” 的场景,通过 Some 和 None 避免空指针错误,是仓颉中处理不确定性的常用方式。

Option<T> 类型 —— 一种安全处理“可能无值”情况的机制。Option 类型通过Some(有值)和None(无值)两种状态,让 "值是否存在" 变得显式可控,配合模式匹配、??操作符、?操作符等工具,能安全、简洁地处理各种可能无值的场景,是仓颉中避免空引用错误的重要机制。

Option 类型使用 enum 定义,它包含两个构造器(constructor):Some 和 None。其中,Some 会携带一个参数,表示有值;None 不带参数,表示无值。当需要表示某个类型可能有值,也可能没有值时,可以选择使用 Option 类型。

Option 是仓颉标准库里内置的泛型枚举,声明如下:

enum Option<T> {
Some(T)   // 表示“有值”,并携带一个 T 类型的数据
None      // 表示“无值”
}

其中,Some() 是仓颉语言中 Option<T> 类型的一个“构造器”(constructor),用来表示“有一个值”。用法示例:

写法                 含义

Some(100)       表示“有一个整数 100”

Some("Hello") 表示“有一个字符串 "Hello"”

Option 类型简洁的写法:

?T 等价于 Option<T>  (官方写为:?Ty 等价于 Option<Ty>。T和Ty都是Type 的缩写,都代表“某个具体的类型”):

?Int64      等价于 Option<Int64>

?String     等价于 Option<String>

?Bool       等价于 Option<Bool>

例如

// 完整写法
let a: Option<Int64> = Some(100)  // 有值:100
let b: Option<String> = Some("Hello")  // 有值:"Hello"
let c: Option<Int64> = None  // 无值

// 简写形式(?Ty)
let d: ?Int64 = Some(200)  // 等价于Option<Int64>
let e: ?String = None  // 等价于Option<String>

Option 类型的解构使用方式

Option 是一种非常常用的类型,所以仓颉为其提供了多种解构【注】方式,以方便 Option 类型的使用,具体包括:模式匹配、getOrThrow 函数、coalescing 操作符(??),以及问号操作符(?)。

【“解构” 在这里的核心含义是:打破 Option 类型的 “包装”,获取 Some 中包含的具体值,或对 None 进行处理】

1.模式匹配(match 语句)

通过match匹配Some和None,显式处理两种状态。 示例:

//将Option<Int64>转换为字符串(有值则返回值的字符串,无值返回"none")
func getString(p: ?Int64): String {match (p) {case Some(x) => "数字:${x}"  // 匹配有值状态,x绑定具体值case None => "没有提供数字"     // 匹配无值状态}
}main() {let a = Some(10)let b: ?Int64 = Noneprintln(getString(a))  // 输出:数字:10println(getString(b))  // 输出:没有提供数字
}

2. coalescing 操作符(??

用于为None提供默认值,语法:e1 ?? e2

  •  若e1是Some(v),返回v

  •  若e1是None,返回e2(e2需与v同类型)

示例:

main() {let a: ?Int64 = Some(5)let b: ?Int64 = Nonelet r1 = a ?? 0 // a是Some(5),返回5let r2 = b ?? 0  // b是None,返回默认值0println(r1)  // 输出:5println(r2)  // 输出:0
}

3. 问号操作符(?

与.、()、[]、{}结合使用,实现对 Option 内部成员的安全访问:

  •  若 Option 是Some(v),则访问v的成员,结果用Some包装

  •  若 Option 是None,则直接返回None(避免空访问错误)

示例:

a.访问结构体 / 类的成员(. 操作):

// 定义一个结构体
struct R {public var a: Int64public init(a: Int64) {this.a = a}
}main() {let r = R(100)let x: ?R = Some(r)  // 有值的Optionlet y: ?R = None     // 无值的Optionlet r1 = x?.a  // x是Some(r),访问r.a,结果为Some(100)let r2 = y?.a  // y是None,直接返回Noneprintln(r1)  // 输出:Some(100)println(r2)  // 输出:None
}

b.多层访问

问号操作符支持链式调用,任意一层为None则整体返回None:

class A {public var b: B = B()  // A包含B类型的b
}class B {public var c: ?C = C()  // B包含Option<C>类型的c(有值)public var c1: ?C = None // B包含Option<C>类型的c1(无值)
}class C {public var d: Int64 = 100  // C包含Int64类型的d
}main() {let a: ?A = Some(A())  // 有值的Option<A>// 多层访问:a?.b.c?.d// a是Some,b存在;c是Some,d存在 → 结果为Some(100)let r1 = a?.b.c?.d// a?.b.c1?.d:c1是None → 结果为Nonelet r2 = a?.b.c1?.dprintln(r1)  // 输出:Some(100)println(r2)  // 输出:None
}

4. getOrThrow 函数

用于直接获取Some中的值,若为None则抛出异常(需配合try-catch处理):

main() {let a: ?Int64 = Some(8)let b: ?Int64 = None// 获取a的值(成功)let r1 = a.getOrThrow()println(r1)  // 输出:8// 获取b的值(失败,抛出异常)try {let r2 = b.getOrThrow()} catch (e: NoneValueException) {println("捕获异常:b是None")  // 输出:捕获异常:b是None}
}

Option 类型主要用于以下场景:

1.     处理可能为空的返回值:如函数可能返回有效结果或无结果(避免返回 null)

2.     安全的成员访问:通过?操作符避免访问空对象的成员

3.     简化错误处理:用None表示 "无结果" 类错误,替代复杂的错误判断

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/97858.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/97858.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

javaEE-Spring IOCDI

目录 1、什么是Spring&#xff1a; 2.什么是IoC: 3. 什么是控制反转呢? 4.IoC容器具备以下优点: 5.DI是什么&#xff1a; 依赖注⼊方法&#xff1a; 三种注入方法的优缺点&#xff1a; Autowired注解注入存在的问题&#xff1a; Autowired和Resource的区别&#xff…

TensorFlow Lite 全面解析:端侧部署方案与PyTorch Mobile深度对比

1 TensorFlow Lite 基础介绍 TensorFlow Lite (TFLite) 是 Google 为移动设备&#xff08;Android, iOS&#xff09;、微控制器&#xff08;Microcontrollers&#xff09;和其他嵌入式设备&#xff08;如 Raspberry Pi&#xff09;开发的轻量级深度学习推理框架。它的核心目标是…

mapbox进阶,使用jsts实现平角缓冲区

👨‍⚕️ 主页: gis分享者 👨‍⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅! 👨‍⚕️ 收录于专栏:mapbox 从入门到精通 文章目录 一、🍀前言 1.1 ☘️mapboxgl.Map 地图对象 1.2 ☘️mapboxgl.Map style属性 1.3 ☘️jsts myBufferOp 缓冲区生成对对象 …

linux装好显卡后如何检查

背景&#xff1a;客户通知装好了显卡&#xff0c;我们去机器上查看一下一. 使用到的命令 watch -n 1 nvidia-smi 可实时查看gpu的使用率nvidia-smi 之查看一次 二、查看内存和显存 内存使用命令 free -h,显存使用 nvidia-smi 这只是查看的navidia, 其他品牌的会不一样

人工智能深度学习——卷积神经网络(CNN)

一、图像卷积运算 对图像矩阵与滤波器矩阵进行对应相乘再求和运算&#xff0c;转化得到新的矩阵。 作用&#xff1a;快速定位图像中某些边缘特征 英文&#xff1a;convolution&#xff08;CNN&#xff09;池化层实现维度缩减 池化&#xff1a;按照一个固定规则对图像矩阵进行处…

SaaS 建站从 0 到 1 教程:Vue 动态域名 + 后端子域名管理 + Nginx 配置

SaaS 建站从 0 到 1 教程&#xff1a;Vue 动态域名 后端子域名管理 Nginx 配置 一、什么是 SaaS 建站&#xff1f; SaaS&#xff08;Software as a Service&#xff09;建站&#xff0c;就是通过一套统一的系统&#xff0c;支持用户在线注册、绑定域名、快速生成专属网站。…

关于神经网络中回归的概念

神经网络中的回归详解 引言 神经网络&#xff08;NeuralNetworks&#xff09;是一种强大的机器学习模型&#xff0c;可用于分类和回归任务。本文聚焦于神经网络中的回归&#xff08;Regression&#xff09;&#xff0c;即预测连续输出值&#xff08;如房价、温度&#xff09;。…

JAVASCRIPT 前端数据库-V9--仙盟数据库架构-—仙盟创梦IDE

老版本 在v1 版本中我们讲述了 基础版的应用JAVASCRIPT 前端数据库-V1--仙盟数据库架构-—-—仙盟创梦IDE-CSDN博客接下载我们做一个更复杂的的其他场景由于&#xff0c;V1查询字段必须 id接下来我们修改了了代码JAVASCRIPT 前端数据库-V2--仙盟数据库架构-—-—仙盟创梦IDE-CS…

k8s核心资料基本操作

NamespaceNamespace是kubernetes系统中的一种非常重要资源&#xff0c;它的主要作用是用来实现多套环境的资源隔离或者多租户的资源隔离。默认情况下&#xff0c;kubernetes集群中的所有的Pod都是可以相互访问的。但是在实际中&#xff0c;可能不想让两个Pod之间进行互相的访问…

PostgreSQL——分区表

分区表一、分区表的意义二、传统分区表2.1、继承表2.2、创建分区表2.3、使用分区表2.4、查询父表还是子表2.5、constraint_exclusion参数2.6、添加分区2.7、删除分区2.8、分区表相关查询2.9、传统分区表注意事项三、内置分区表3.1、创建分区表3.2、使用分区表3.3、内置分区表原…

Linux任务调度全攻略

Linux下的任务调度分为两类&#xff0c;系统任务调度和用户任务调度。系统任务调度&#xff1a;系统周期性所要执行的工作&#xff0c;比如写缓存数据到硬盘、日志清理等。在/etc目录下有一个crontab文件&#xff0c;这个就是系统任务调度的配置文件。/etc/crontab文件包括下面…

回溯算法通关秘籍:像打怪一样刷题

&#x1f680; 回溯算法通关秘籍&#xff1a;像打怪一样刷题&#xff01; 各位同学&#xff0c;今天咱们聊聊 回溯算法&#xff08;Backtracking&#xff09;。它听起来玄乎&#xff0c;但其实就是 “暴力搜索 剪枝” 的优雅版。 打个比方&#xff1a;回溯就是在迷宫里探险&am…

嵌入式Linux常用命令

&#x1f4df; 核心文件与目录操作pwd-> 功能: 打印当前工作目录的绝对路径。-> 示例: pwd -> 输出 /home/user/projectls [选项] [目录]-> 功能: 列出目录内容。-> 常用选项:-l: 长格式显示&#xff08;详细信息&#xff09;-a: 显示所有文件&#xff08;包括隐…

深入理解 Linux 内核进程管理

在 Linux 系统中&#xff0c;进程是资源分配和调度的基本单位&#xff0c;内核对进程的高效管理直接决定了系统的性能与稳定性。本文将从进程描述符的结构入手&#xff0c;逐步剖析进程的创建、线程实现与进程终结的完整生命周期&#xff0c;带您深入理解 Linux 内核的进程管理…

ACP(三):让大模型能够回答私域知识问题

让大模型能够回答私域知识问题 未经过特定训练答疑机器人&#xff0c;是无法准确回答“我们公司项目管理用什么工具”这类内部问题。根本原因在于&#xff0c;大模型的知识来源于其训练数据&#xff0c;这些数据通常是公开的互联网信息&#xff0c;不包含任何特定公司的内部文档…

使用Xterminal连接Linux服务器

使用Xterminal连接Linux服务器&#xff08;VMware虚拟机&#xff09;的步骤如下&#xff0c;前提是虚拟机已获取IP&#xff08;如 192.168.31.105&#xff09;且网络互通&#xff1a; 一、准备工作&#xff08;服务器端确认&#xff09;确保SSH服务已安装并启动 Linux服务器需要…

ChatBot、Copilot、Agent啥区别

以下内容为AI生成ChatBot&#xff08;聊天机器人&#xff09;、Copilot&#xff08;副驾驶&#xff09;和Agent&#xff08;智能体/代理&#xff09;是AI应用中常见的三种形态&#xff0c;它们在人机交互、自动化程度和任务处理能力上有着显著的区别。特征维度ChatBot (聊天机器…

2025 年大语言模型架构演进:DeepSeek V3、OLMo 2、Gemma 3 与 Mistral 3.1 核心技术剖析

编者按&#xff1a; 在 Transformer 架构诞生八年之际&#xff0c;我们是否真的见证了根本性的突破&#xff0c;还是只是在原有设计上不断打磨&#xff1f;今天我们为大家带来的这篇文章&#xff0c;作者的核心观点是&#xff1a;尽管大语言模型在技术细节上持续优化&#xff0…

基于Matlab GUI的心电信号QRS波群检测与心率分析系统

心电信号&#xff08;Electrocardiogram, ECG&#xff09;是临床诊断心脏疾病的重要依据&#xff0c;其中 QRS 波群的准确检测对于心率分析、心律失常诊断及自动化心电分析系统具有核心意义。本文设计并实现了一套基于 MATLAB GUI 的心电信号处理与分析系统&#xff0c;集成了数…

1台SolidWorks服务器能带8-10人并发使用

在工业设计和机械工程领域&#xff0c;SolidWorks作为主流的三维CAD软件&#xff0c;其服务器部署方案直接影响企业协同效率。通过云飞云共享云桌面技术实现多人并发使用SolidWorks时&#xff0c;实际承载量取决于硬件配置、网络环境、软件优化等多维度因素的综合作用。根据专业…