活动公开课
网页设计01
数据库设计01
仓颉开发语言01
鸿蒙开发01-HarmonyOS第一课
CPU眼中的C++
本文档使用 MrDoc 发布
-
+
首页
仓颉开发语言01
## 在线体验工具 https://cangjie-lang.cn/experience ## 初识仓颉语言 <div _ngcontent-apy-c173="" class="markdown-body ng-star-inserted" style="position: relative;"> <div id="body385669987144659"><p id="ZH-CN_TOPIC_0000002048298028__p546012449144659">仓颉编程语言是一种面向全场景应用开发的通用编程语言,可以兼顾开发效率和运行性能,并提供良好的编程体验,主要具有如下特点:</p> <ul id="ZH-CN_TOPIC_0000002048298028__ul1437375420144659"><li id="li1583507010144659"><strong>语法简明高效</strong>:仓颉编程语言提供了一系列简明高效的语法,旨在减少冗余书写、提升开发效率,例如插值字符串、主构造函数、Flow 表达式、match、if-let、while-let 和重导出等语法,让开发者可以用较少编码表达相关逻辑。</li></ul> <p id="ZH-CN_TOPIC_0000002048298028__p3811141254914"></p> <ul id="ZH-CN_TOPIC_0000002048298028__ul1581941234914"><li id="li68185121499"><strong>多范式编程</strong>:仓颉编程语言支持函数式、命令式和面向对象等多范式编程,融合了高阶函数、代数数据类型、模式匹配、泛型等函数式语言的先进特性,还有封装、接口、继承、子类型多态等支持模块化开发的面向对象语言特性,以及值类型、全局函数等简洁高效的命令式语言特性。开发者可以根据开发偏好或应用场景,选用不同的编程范式。</li></ul> <p id="ZH-CN_TOPIC_0000002048298028__p24431717494"></p> <ul id="ZH-CN_TOPIC_0000002048298028__ul1850617194918"><li id="li74919177498"><strong>类型安全</strong>:仓颉编程语言是静态强类型语言,通过编译时类型检查尽早识别程序错误,降低运行时风险,也便于代码维护。同时,仓颉编译器提供了强大的类型推断能力,可以减少类型标注工作,提高开发效率。</li></ul> <p id="ZH-CN_TOPIC_0000002048298028__p1384191934910"></p> <ul id="ZH-CN_TOPIC_0000002048298028__ul20390171918492"><li id="li13893194495"><strong>内存安全</strong>:仓颉编程语言支持自动内存管理,并在运行时进行数组下标越界检查、溢出检查等,确保运行时内存安全。</li></ul> <p id="ZH-CN_TOPIC_0000002048298028__p336602117493"></p> <ul id="ZH-CN_TOPIC_0000002048298028__ul3371182124919"><li id="li23714217497"><strong>高效并发</strong>:仓颉编程语言提供了用户态轻量化线程(原生协程),以及简单易用的并发编程机制,保证并发场景的高效开发和运行。</li></ul> <p id="ZH-CN_TOPIC_0000002048298028__p104565233499"></p> <ul id="ZH-CN_TOPIC_0000002048298028__ul44606237492"><li id="li18460132314914"><strong>兼容语言生态</strong>:仓颉编程语言支持和 C 等主流编程语言的互操作,并采用便捷的声明式编程范式,可实现对其他语言库的高效复用和生态兼容。</li></ul> <p id="ZH-CN_TOPIC_0000002048298028__p15764132574919"></p> <ul id="ZH-CN_TOPIC_0000002048298028__ul1976892594918"><li id="li57681725154918"><strong>领域易扩展</strong>:仓颉编程语言提供了基于词法宏的元编程能力,支持在编译时变换代码,此外,还提供了尾随 lambda、属性、操作符重载、部分关键字可省略等特性,开发者可由此深度定制程序的语法和语义,有利于内嵌式领域专用语言(Embedded Domain Specific Languages,EDSL)的构建。</li></ul> <p id="ZH-CN_TOPIC_0000002048298028__p113506282499"></p> <ul id="ZH-CN_TOPIC_0000002048298028__ul113533289494"><li id="li183531928124912"><strong>助力 UI 开发</strong>:UI 开发是构建端侧应用的重要环节,基于仓颉编程语言的元编程和尾随 lambda 等特性,可以搭建声明式 UI 开发框架,提升 UI 开发效率和体验。</li></ul> <p id="ZH-CN_TOPIC_0000002048298028__p895673044917"></p> <ul id="ZH-CN_TOPIC_0000002048298028__ul29581330174912"><li id="li8958203015493"><strong>内置库功能丰富</strong>:仓颉编程语言提供了功能丰富的内置库,涉及数据结构、常用算法、数学计算、正则匹配、系统交互、文件操作、网络通信、数据库访问、日志打印、解压缩、编解码、加解密和序列化等功能。</li></ul> </div> <div></div></div> ## 一、标识符 <div _ngcontent-apy-c173="" id="mark" class="idpContent"><div _ngcontent-apy-c173="" class="markdown-body ng-star-inserted" style="position: relative;"> <div id="body726490168144659"><p id="ZH-CN_TOPIC_0000002048139768__p424621717144659">在仓颉编程语言中,开发者可以给一些程序元素命名,这些名字也被称为“标识符”,标识符分为普通标识符和原始标识符两类,它们分别遵从不同的命名规则。</p> <p id="ZH-CN_TOPIC_0000002048139768__p1309710005144659"><strong>普通标识符</strong>不能和仓颉关键字相同,可以取自以下两类字符序列:</p> <ul id="ZH-CN_TOPIC_0000002048139768__ul1141489202144659"><li id="li2140035790144659">由 XID_Start 字符开头,后接任意长度的 XID_Continue 字符</li><li id="li723360665144659">由一个_开头,后接至少一个 XID_Continue 字符</li></ul> <p id="ZH-CN_TOPIC_0000002048139768__p558804956144659">其中,XID_Start、XID_Continue 定义见<a href="https://www.unicode.org/reports/tr31/tr31-37.html" target="_blank">Unicode 标准</a>。仓颉使用 Unicode 标准 15.0.0。</p> <p id="ZH-CN_TOPIC_0000002048139768__p1683789174144659">仓颉把所有标识符识别为 <a href="https://www.unicode.org/reports/tr15/tr15-53.html" target="_blank">Normalization Form C (NFC)</a> 后的形式。两个标识符如果在 NFC 后相等,则认为是相同的标识符。</p> <p id="ZH-CN_TOPIC_0000002048139768__p983340137144659">例如,以下每行字符串都是合法的普通标识符:</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002048139768__screen145213591144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-variable">abc</span></li><li><span class="hljs-variable">_abc</span></li><li><span class="hljs-variable">abc_</span></li><li><span class="hljs-variable">a1b2c3</span></li><li><span class="hljs-variable">a_b_c</span></li><li><span class="hljs-variable">a1_b2_c3</span></li><li><span class="hljs-variable">仓颉</span></li><li><span class="hljs-variable">__</span>こんにちは</li></ol></pre> <p id="ZH-CN_TOPIC_0000002048139768__p2075627117144659">以下每行字符串都是不合法的普通标识符:</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002048139768__screen1308256032144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-variable">ab</span>&<span class="hljs-variable">c</span> <span class="hljs-comment">// 使用了非法字符 “&”</span></li><li><span class="hljs-number">3</span><span class="hljs-variable">abc</span> <span class="hljs-comment">// 数字不能出现在头部</span></li><li><span class="hljs-keyword">while</span> <span class="hljs-comment">// 不能使用仓颉关键字</span></li></ol></pre> <p id="ZH-CN_TOPIC_0000002048139768__p1066249201144659"><strong>原始标识符</strong>是在普通标识符或仓颉关键字的外面加上一对反引号,主要用于将仓颉关键字作为标识符的场景。</p> <p id="ZH-CN_TOPIC_0000002048139768__p191511322144659">例如,以下每行字符串都是合法的原始标识符:</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002048139768__screen871576108144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-variable">`abc`</span></li><li><span class="hljs-variable">`_abc`</span></li><li><span class="hljs-variable">`a1b2c3`</span></li><li><span class="hljs-variable">`if`</span></li><li><span class="hljs-variable">`while`</span></li><li>`<span class="hljs-variable">a</span>֮̀̅̕<span class="hljs-variable">b</span>`</li></ol></pre> <p id="ZH-CN_TOPIC_0000002048139768__p273584629144659">以下每行字符串,由于反引号内的部分是不合法的普通标识符,所以它们整体也是不合法的原始标识符:</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002048139768__screen900470084144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li>`<span class="hljs-variable">ab</span>&<span class="hljs-variable">c</span>`</li><li>`<span class="hljs-number">3</span><span class="hljs-variable">abc</span>`</li></ol></pre> </div> <div></div></div><!----><!----></div> ## 二、程序结构 <div _ngcontent-apy-c173="" class="markdown-body ng-star-inserted" style="position: relative;"> <div id="body388887212144659"><p id="ZH-CN_TOPIC_0000002084338673__p1564565364144659">通常,我们都会在扩展名为 .cj 的文本文件中编写仓颉程序,这些程序和文件也被称为源代码和源文件,在程序开发的最后阶段,这些源代码将被编译为特定格式的二进制文件。</p> <p id="ZH-CN_TOPIC_0000002084338673__p1913539456144659">在仓颉程序的顶层作用域中,可以定义一系列的变量、函数和自定义类型(如 struct、class、enum 和 interface 等),其中的变量和函数分别被称为<strong>全局变量</strong>和<strong>全局函数</strong>。如果要将仓颉程序编译为可执行文件,您需要在顶层作用域中定义一个 main 函数作为<strong>程序入口</strong>,它可以有 Array<String> 类型的参数,也可以没有参数,它的返回值类型可以是整数类型或 Unit 类型。</p> <div><div class="hw-editor-tip warn"><div class="title">注意</div><div class="content"> <p id="ZH-CN_TOPIC_0000002084338673__p1584668573144659">定义 main 函数时,不需要写 func 修饰符。此外,如果需要获取程序启动时的命令行参数,可以声明和使用 Array<String> 类型参数。</p> </div></div></div> <p id="ZH-CN_TOPIC_0000002084338673__p1046900934144659">例如在以下程序中,我们在顶层作用域定义了全局变量 a 和全局函数 b,还有自定义类型 C、D 和 E,以及作为程序入口的 main 函数。</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002084338673__screen981202835144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-comment">// example.cj</span></li><li><span class="hljs-keyword">let</span> <span class="hljs-variable">a</span> = <span class="hljs-number">2023</span></li><li><span class="hljs-keyword">func</span> <span class="hljs-title function_">b</span>() {}</li><li><span class="hljs-keyword">struct</span> <span class="hljs-title class_">C</span> {}</li><li><span class="hljs-keyword">class</span> <span class="hljs-title class_">D</span> {}</li><li><span class="hljs-keyword">enum</span> <span class="hljs-title class_">E</span> { <span class="hljs-variable">F</span> | <span class="hljs-variable">G</span> }</li><li> </li><li><span class="hljs-keyword">main</span>() {</li><li> <span class="hljs-title function_">println</span>(<span class="hljs-variable">a</span>)</li><li>}</li></ol></pre> <p id="ZH-CN_TOPIC_0000002084338673__p814249808144659">在非顶层作用域中不能定义上述自定义类型,但可以定义变量和函数,称之为<strong>局部变量</strong>和<strong>局部函数</strong>。特别地,对于定义在自定义类型中的变量和函数,称之为<strong>成员变量</strong>和<strong>成员函数</strong>。</p> <div><div class="hw-editor-tip warn"><div class="title">注意</div><div class="content"> <p id="ZH-CN_TOPIC_0000002084338673__p386990246144659">enum 和 interface 中仅支持定义成员函数,不支持定义成员变量。</p> </div></div></div> <p id="ZH-CN_TOPIC_0000002084338673__p321746630144659">例如在以下程序中,我们在顶层作用域定义了全局函数 a 和自定义类型 A,在函数 a 中定义了局部变量 b 和局部函数 c,在自定义类型 A 中定义了成员变量 b 和成员函数 c。</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002084338673__screen1503929990144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-comment">// example.cj</span></li><li><span class="hljs-keyword">func</span> <span class="hljs-title function_">a</span>() {</li><li> <span class="hljs-keyword">let</span> <span class="hljs-variable">b</span> = <span class="hljs-number">2023</span></li><li> <span class="hljs-keyword">func</span> <span class="hljs-title function_">c</span>() {</li><li> <span class="hljs-title function_">println</span>(<span class="hljs-variable">b</span>)</li><li> }</li><li> <span class="hljs-title function_">c</span>()</li><li>}</li><li> </li><li><span class="hljs-keyword">class</span> <span class="hljs-title class_">A</span> {</li><li> <span class="hljs-keyword">let</span> <span class="hljs-variable">b</span> = <span class="hljs-number">2024</span></li><li> <span class="hljs-keyword">public</span> <span class="hljs-keyword">func</span> <span class="hljs-title function_">c</span>() {</li><li> <span class="hljs-title function_">println</span>(<span class="hljs-variable">b</span>)</li><li> }</li><li>}</li><li> </li><li><span class="hljs-keyword">main</span>() {</li><li> <span class="hljs-title function_">a</span>()</li><li> <span class="hljs-title function_">A</span>().<span class="hljs-title function_">c</span>()</li><li>}</li></ol></pre> <p id="ZH-CN_TOPIC_0000002084338673__p1015838639144659">运行以上程序,将输出:</p> <pre class="text prettyprint linenums hljs language-plaintext" id="ZH-CN_TOPIC_0000002084338673__screen1690306334144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li>2023</li><li>2024</li></ol></pre> <div class="tiledSection"><h2 id="变量">变量<i class="anchorIcon" anchorid="变量" tips="复制节点链接"></i></h2><p id="ZH-CN_TOPIC_0000002084338673__p1865433950144659">在仓颉编程语言中,一个变量由对应的变量名、数据(值)和若干属性构成,开发者通过变量名访问变量对应的数据,但访问操作需要遵从相关属性的约束(如数据类型、可变性和可见性等)。</p> <p id="ZH-CN_TOPIC_0000002084338673__p1485872232144659">变量定义的具体形式为:</p> <pre class="text prettyprint linenums hljs language-plaintext" id="ZH-CN_TOPIC_0000002084338673__screen1432370376144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li>修饰符 变量名: 变量类型 = 初始值</li></ol></pre> <p id="ZH-CN_TOPIC_0000002084338673__p236738143144659">其中<strong>修饰符</strong>用于设置变量的各类属性,可以有一个或多个,常用的修饰符包括:</p> <ul id="ZH-CN_TOPIC_0000002084338673__ul257852162144659"><li id="li1595925108144659">可变性修饰符:let 与 var,分别对应不可变和可变属性,可变性决定了变量被初始化后其值还能否改变,仓颉变量也由此分为不可变变量和可变变量两类。</li><li id="li475858322144659">可见性修饰符:private 与 public 等,影响全局变量和成员变量的可引用范围,详见后续章节的相关介绍。</li><li id="li691299831144659">静态性修饰符:static,影响成员变量的存储和引用方式,详见后续章节的相关介绍。</li></ul> <p id="ZH-CN_TOPIC_0000002084338673__p798305787144659">在定义仓颉变量时,可变性修饰符是必要的,在此基础上,还可以根据需要添加其他修饰符。</p> <ul id="ZH-CN_TOPIC_0000002084338673__ul1950538081144659"><li id="li631601028144659"><strong>变量名</strong>应是一个合法的仓颉标识符。</li><li id="li395947169144659"><strong>变量类型</strong>指定了变量所持有数据的类型。当初始值具有明确类型时,可以省略变量类型标注,此时编译器可以自动推断出变量类型。</li><li id="li658345507144659"><strong>初始值</strong>是一个仓颉表达式,用于初始化变量,如果标注了变量类型,需要保证初始值类型和变量类型一致。在定义全局变量或静态成员变量时,必须指定初始值。在定义局部变量或实例成员变量时,可以省略初始值,但需要标注变量类型,同时要在此变量被引用前完成初始化,否则编译会报错。</li></ul> <p id="ZH-CN_TOPIC_0000002084338673__p94681685144659">例如,下列程序定义了两个 Int64 类型的不可变变量 a 和可变变量 b,随后修改了变量 b 的值,并调用 println 函数打印 a 与 b 的值。</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002084338673__screen1879358240144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">main</span>() {</li><li> <span class="hljs-keyword">let</span> <span class="hljs-variable">a</span>: <span class="hljs-keyword">Int64</span> = <span class="hljs-number">20</span></li><li> <span class="hljs-keyword">var</span> <span class="hljs-variable">b</span>: <span class="hljs-keyword">Int64</span> = <span class="hljs-number">12</span></li><li> <span class="hljs-variable">b</span> = <span class="hljs-number">23</span></li><li> <span class="hljs-title function_">println</span>(<span class="hljs-string">"<span class="hljs-subst">${<span class="hljs-variable">a</span>}</span><span class="hljs-subst">${<span class="hljs-variable">b</span>}</span>"</span>)</li><li>}</li></ol></pre> <p id="ZH-CN_TOPIC_0000002084338673__p184976380144659">编译运行此程序,将输出:</p> <pre class="text prettyprint linenums hljs language-plaintext" id="ZH-CN_TOPIC_0000002084338673__screen992567970144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li>2023</li></ol></pre> <p id="ZH-CN_TOPIC_0000002084338673__p1761681910144659">如果尝试修改不可变变量,编译时会报错,例如:</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002084338673__screen1095369121144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">main</span>() {</li><li> <span class="hljs-keyword">let</span> <span class="hljs-variable">pi</span>: <span class="hljs-keyword">Float64</span> = <span class="hljs-number">3.14159</span></li><li> <span class="hljs-variable">pi</span> = <span class="hljs-number">2.71828</span> <span class="hljs-comment">// Error, cannot assign to immutable value</span></li><li>}</li></ol></pre> <p id="ZH-CN_TOPIC_0000002084338673__p376368658144659">当初始值具有明确类型时,可以省略变量类型标注,例如:</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002084338673__screen1845198701144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">main</span>() {</li><li> <span class="hljs-keyword">let</span> <span class="hljs-variable">a</span>: <span class="hljs-keyword">Int64</span> = <span class="hljs-number">2023</span></li><li> <span class="hljs-keyword">let</span> <span class="hljs-variable">b</span> = <span class="hljs-variable">a</span></li><li> <span class="hljs-title function_">println</span>(<span class="hljs-string">"a - b = <span class="hljs-subst">${<span class="hljs-variable">a</span> - <span class="hljs-variable">b</span>}</span>"</span>)</li><li>}</li></ol></pre> <p id="ZH-CN_TOPIC_0000002084338673__p1413122749144659">其中变量 b 的类型可以由其初值 a 的类型自动推断为 Int64,所以此程序也可以被正常编译和运行,将输出:</p> <pre class="text prettyprint linenums hljs language-plaintext" id="ZH-CN_TOPIC_0000002084338673__screen1388919445144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li>a - b = 0</li></ol></pre> <p id="ZH-CN_TOPIC_0000002084338673__p1129748323144659">在定义局部变量时,可以不进行初始化,但一定要在变量被引用前赋予初值,例如:</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002084338673__screen135056002144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">main</span>() {</li><li> <span class="hljs-keyword">let</span> <span class="hljs-variable">text</span>: <span class="hljs-title class_">String</span></li><li> <span class="hljs-variable">text</span> = <span class="hljs-string">"仓颉造字"</span></li><li> <span class="hljs-title function_">println</span>(<span class="hljs-variable">text</span>)</li><li>}</li></ol></pre> <p id="ZH-CN_TOPIC_0000002084338673__p2069506074144659">编译运行此程序,将输出:</p> <pre class="text prettyprint linenums hljs language-plaintext" id="ZH-CN_TOPIC_0000002084338673__screen563428674144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li>仓颉造字</li></ol></pre> <p id="ZH-CN_TOPIC_0000002084338673__p1106005084144659">在定义全局变量和静态成员变量时必须初始化,否则编译会报错,例如:</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002084338673__screen2140722309144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-comment">// example.cj</span></li><li><span class="hljs-keyword">let</span> <span class="hljs-variable">global</span>: <span class="hljs-keyword">Int64</span> <span class="hljs-comment">// Error, variable in top-level scope must be initialized</span></li></ol></pre> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002084338673__screen1499282186144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-comment">// example.cj</span></li><li><span class="hljs-keyword">class</span> <span class="hljs-title class_">Player</span> {</li><li> <span class="hljs-keyword">static</span> <span class="hljs-keyword">let</span> <span class="hljs-variable">score</span>: <span class="hljs-keyword">Int32</span> <span class="hljs-comment">// Error, static variable 'score' needs to be initialized when declaring</span></li><li>}</li></ol></pre> </div> <div class="tiledSection"><h3 id="值类型和引用类型变量" class="firsth2">值类型和引用类型变量<i class="anchorIcon" anchorid="值类型和引用类型变量" tips="复制节点链接"></i></h3><p id="ZH-CN_TOPIC_0000002084338673__p1668916068144659">程序在运行阶段,只有指令流转和数据变换,仓颉程序中的各种标识符已不复存在。由此可见,编译器使用了一些机制,将这些名字和编程所取用的数据实体/存储空间绑定起来。</p> <p id="ZH-CN_TOPIC_0000002084338673__p460197019144659">从编译器实现层面看,任何变量总会关联一个值(一般是通过内存地址/寄存器关联),只是在使用时,对有些变量,我们将直接取用这个值本身,这被称为<strong>值类型变量</strong>,而对另一些变量,我们把这个值作为索引、取用这个索引指示的数据,这被称为<strong>引用类型变量</strong>。值类型变量通常在线程栈上分配,每个变量都有自己的数据副本;引用类型变量通常在进程堆中分配,多个变量可引用同一数据对象,对一个变量执行的操作可能会影响其他变量。</p> <p id="ZH-CN_TOPIC_0000002084338673__p956628100144659">从语言层面看,值类型变量对它所绑定的数据/存储空间是独占的,而引用类型变量所绑定的数据/存储空间可以和其他引用类型变量共享。</p> <p id="ZH-CN_TOPIC_0000002084338673__p1625288853144659">基于上述原理,在使用值类型变量和引用类型变量时,会存在一些行为差异,以下几点值得注意:</p> <ol id="ZH-CN_TOPIC_0000002084338673__ol373338302144659"><li id="li1599641833144659">在给值类型变量赋值时,一般会产生拷贝操作,且原来绑定的数据/存储空间被覆写。在给引用类型变量赋值时,只是改变了引用关系,原来绑定的数据/存储空间不会被覆写。</li><li id="li344125182144659">用 let 定义的变量,要求变量被初始化后都不能再赋值。对于引用类型,这只是限定了引用关系不可改变,但是所引用的数据是可以被修改的。</li></ol> <p id="ZH-CN_TOPIC_0000002084338673__p687598062144659">在仓颉编程语言中,class 和 Array 等类型属于引用类型,其他基础数据类型和 struct 等类型属于值类型。</p> <p id="ZH-CN_TOPIC_0000002084338673__p288064828144659">例如,以下程序演示了 struct 和 class 类型变量的行为差异:</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002084338673__screen1222516224144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">struct</span> <span class="hljs-title class_">Copy</span> {</li><li> <span class="hljs-keyword">var</span> <span class="hljs-variable">data</span> = <span class="hljs-number">2012</span></li><li>}</li><li> </li><li><span class="hljs-keyword">class</span> <span class="hljs-title class_">Share</span> {</li><li> <span class="hljs-keyword">var</span> <span class="hljs-variable">data</span> = <span class="hljs-number">2012</span></li><li>}</li><li> </li><li><span class="hljs-keyword">main</span>() {</li><li> <span class="hljs-keyword">let</span> <span class="hljs-variable">c1</span> = <span class="hljs-title function_">Copy</span>()</li><li> <span class="hljs-keyword">var</span> <span class="hljs-variable">c2</span> = <span class="hljs-variable">c1</span></li><li> <span class="hljs-variable">c2</span>.<span class="hljs-variable">data</span> = <span class="hljs-number">2023</span></li><li> <span class="hljs-title function_">println</span>(<span class="hljs-string">"<span class="hljs-subst">${<span class="hljs-variable">c1</span>.<span class="hljs-variable">data</span>}</span>, <span class="hljs-subst">${<span class="hljs-variable">c2</span>.<span class="hljs-variable">data</span>}</span>"</span>)</li><li> </li><li> <span class="hljs-keyword">let</span> <span class="hljs-variable">s1</span> = <span class="hljs-title function_">Share</span>()</li><li> <span class="hljs-keyword">let</span> <span class="hljs-variable">s2</span> = <span class="hljs-variable">s1</span></li><li> <span class="hljs-variable">s2</span>.<span class="hljs-variable">data</span> = <span class="hljs-number">2023</span></li><li> <span class="hljs-title function_">println</span>(<span class="hljs-string">"<span class="hljs-subst">${<span class="hljs-variable">s1</span>.<span class="hljs-variable">data</span>}</span>, <span class="hljs-subst">${<span class="hljs-variable">s2</span>.<span class="hljs-variable">data</span>}</span>"</span>)</li><li>}</li></ol></pre> <p id="ZH-CN_TOPIC_0000002084338673__p772082844144659">运行以上程序,将输出:</p> <pre class="text prettyprint linenums hljs language-plaintext" id="ZH-CN_TOPIC_0000002084338673__screen1110803297144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li>2012, 2023</li><li>2023, 2023</li></ol></pre> <p id="ZH-CN_TOPIC_0000002084338673__p721640456144659">由此可以看出,对于值类型的 Copy 类型变量,在赋值时总是获取 Copy 实例的拷贝,如 c2 = c1,随后对 c2 成员的修改并不影响 c1。对于引用类型的 Share 类型变量,在赋值时将建立变量和实例之间的引用关系,如 s2 = s1,随后对 s2 成员的修改会影响 s1。</p> <p id="ZH-CN_TOPIC_0000002084338673__p1261529070144659">如果将以上程序中的 var c2 = c1 改成 let c2 = c1,则编译会报错,例如:</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002084338673__screen1319132003144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">struct</span> <span class="hljs-title class_">Copy</span> {</li><li> <span class="hljs-keyword">var</span> <span class="hljs-variable">data</span> = <span class="hljs-number">2012</span></li><li>}</li><li> </li><li><span class="hljs-keyword">main</span>() {</li><li> <span class="hljs-keyword">let</span> <span class="hljs-variable">c1</span> = <span class="hljs-title function_">Copy</span>()</li><li> <span class="hljs-keyword">let</span> <span class="hljs-variable">c2</span> = <span class="hljs-variable">c1</span></li><li> <span class="hljs-variable">c2</span>.<span class="hljs-variable">data</span> = <span class="hljs-number">2023</span> <span class="hljs-comment">// Error, cannot assign to immutable value</span></li><li>}</li></ol></pre> </div> <div class="tiledSection"><h2 id="作用域">作用域<i class="anchorIcon" anchorid="作用域" tips="复制节点链接"></i></h2><p id="ZH-CN_TOPIC_0000002084338673__p25448862144659">在前文中,我们初步介绍了如何给仓颉程序元素命名,实际上,除了变量,我们还可以给函数和自定义类型等命名,在程序中将使用这些名字访问对应的程序元素。</p> <p id="ZH-CN_TOPIC_0000002084338673__p5263084144659">但在实际应用中,需要考虑一些特殊情况:</p> <ul id="ZH-CN_TOPIC_0000002084338673__ul747760183144659"><li id="li809426535144659">当程序规模较大时,那些简短的名字很容易重复,即产生命名冲突。</li><li id="li576007339144659">结合运行时考虑,在有些代码片段中,另一些程序元素是无效的,对它们的引用会导致运行时错误。</li><li id="li1534911142144659">在某些逻辑构造中,为了表达元素之间的包含关系,不应通过名字直接访问子元素,而是要通过其父元素名间接访问。</li></ul> <p id="ZH-CN_TOPIC_0000002084338673__p231793089144659">为了应对这些问题,现代编程语言引入了“作用域”的概念及设计,将名字和程序元素的绑定关系限制在一定范围里。不同作用域之间可以是并列或无关的,也可以是嵌套或包含关系。一个作用域将明确我们能用哪些名字访问哪些程序元素,具体规则是:</p> <ol id="ZH-CN_TOPIC_0000002084338673__ol1556578084144659"><li id="li629002885144659">当前作用域中定义的程序元素与名字的绑定关系,在当前作用域和其内层作用域中是有效的,可以通过此名字直接访问对应的程序元素。</li><li id="li1913379380144659">内层作用域中定义的程序元素与名字的绑定关系,在外层作用域中无效。</li><li id="li702956388144659">内层作用域可以使用外层作用域中的名字重新定义绑定关系,根据规则 1,此时内层作用域中的命名相当于遮盖了外层作用域中的同名定义,对此我们称内层作用域的级别比外层作用域的级别高。</li></ol> <p id="ZH-CN_TOPIC_0000002084338673__p169592879144659">在仓颉编程语言中,用一对大括号“{}”包围一段仓颉代码,即构造了一个新的作用域,其中可以继续使用大括号“{}”包围仓颉代码,由此产生了嵌套作用域,这些作用域均服从上述规则。特别的,在一个仓颉源文件中,不被任何大括号“{}”包围的代码,它们所属的作用域被称为“顶层作用域”,即当前文件中“最外层”的作用域,按上述规则,其作用域级别最低。</p> <div><div class="hw-editor-tip warn"><div class="title">注意</div><div class="content"> <p id="ZH-CN_TOPIC_0000002084338673__p1877271688144659">用大括号“{}”包围代码构造作用域时,其中不限于使用表达式,还可以定义函数和自定义类型等。</p> </div></div></div> <p id="ZH-CN_TOPIC_0000002084338673__p356422113144659">例如在以下名为 test.cj 的仓颉源文件里,在顶层作用域中定义了名字 element,它和字符串“仓颉”绑定,而 main 和 if 引导的代码块中也定义了名字 element,分别对应整数 9 和整数 2023。由上述作用域规则,在第 4 行,element 的值为“仓颉”,在第 8 行,element 的值为 2023,在第 10 行,element 的值为 9。</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002084338673__screen3315180144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-comment">// test.cj</span></li><li><span class="hljs-keyword">let</span> <span class="hljs-variable">element</span> = <span class="hljs-string">"仓颉"</span></li><li><span class="hljs-keyword">main</span>() {</li><li> <span class="hljs-title function_">println</span>(<span class="hljs-variable">element</span>)</li><li> <span class="hljs-keyword">let</span> <span class="hljs-variable">element</span> = <span class="hljs-number">9</span></li><li> <span class="hljs-keyword">if</span> (<span class="hljs-variable">element</span> > <span class="hljs-number">0</span>) {</li><li> <span class="hljs-keyword">let</span> <span class="hljs-variable">element</span> = <span class="hljs-number">2023</span></li><li> <span class="hljs-title function_">println</span>(<span class="hljs-variable">element</span>)</li><li> }</li><li> <span class="hljs-title function_">println</span>(<span class="hljs-variable">element</span>)</li><li>}</li></ol></pre> <p id="ZH-CN_TOPIC_0000002084338673__p1286366902144659">运行以上程序,将输出:</p> <pre class="text prettyprint linenums hljs language-plaintext" id="ZH-CN_TOPIC_0000002084338673__screen1379505148144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li>仓颉</li><li>2023</li><li>9</li></ol></pre> </div> </div> <div></div></div> ## 程序结构 <div _ngcontent-apy-c173="" class="markdown-body ng-star-inserted" style="position: relative;"> <div id="body388887212144659"><p id="ZH-CN_TOPIC_0000002084338673__p1564565364144659">通常,我们都会在扩展名为 .cj 的文本文件中编写仓颉程序,这些程序和文件也被称为源代码和源文件,在程序开发的最后阶段,这些源代码将被编译为特定格式的二进制文件。</p> <p id="ZH-CN_TOPIC_0000002084338673__p1913539456144659">在仓颉程序的顶层作用域中,可以定义一系列的变量、函数和自定义类型(如 struct、class、enum 和 interface 等),其中的变量和函数分别被称为<strong>全局变量</strong>和<strong>全局函数</strong>。如果要将仓颉程序编译为可执行文件,您需要在顶层作用域中定义一个 main 函数作为<strong>程序入口</strong>,它可以有 Array<String> 类型的参数,也可以没有参数,它的返回值类型可以是整数类型或 Unit 类型。</p> <div><div class="hw-editor-tip warn"><div class="title">注意</div><div class="content"> <p id="ZH-CN_TOPIC_0000002084338673__p1584668573144659">定义 main 函数时,不需要写 func 修饰符。此外,如果需要获取程序启动时的命令行参数,可以声明和使用 Array<String> 类型参数。</p> </div></div></div> <p id="ZH-CN_TOPIC_0000002084338673__p1046900934144659">例如在以下程序中,我们在顶层作用域定义了全局变量 a 和全局函数 b,还有自定义类型 C、D 和 E,以及作为程序入口的 main 函数。</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002084338673__screen981202835144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-comment">// example.cj</span></li><li><span class="hljs-keyword">let</span> <span class="hljs-variable">a</span> = <span class="hljs-number">2023</span></li><li><span class="hljs-keyword">func</span> <span class="hljs-title function_">b</span>() {}</li><li><span class="hljs-keyword">struct</span> <span class="hljs-title class_">C</span> {}</li><li><span class="hljs-keyword">class</span> <span class="hljs-title class_">D</span> {}</li><li><span class="hljs-keyword">enum</span> <span class="hljs-title class_">E</span> { <span class="hljs-variable">F</span> | <span class="hljs-variable">G</span> }</li><li> </li><li><span class="hljs-keyword">main</span>() {</li><li> <span class="hljs-title function_">println</span>(<span class="hljs-variable">a</span>)</li><li>}</li></ol></pre> <p id="ZH-CN_TOPIC_0000002084338673__p814249808144659">在非顶层作用域中不能定义上述自定义类型,但可以定义变量和函数,称之为<strong>局部变量</strong>和<strong>局部函数</strong>。特别地,对于定义在自定义类型中的变量和函数,称之为<strong>成员变量</strong>和<strong>成员函数</strong>。</p> <div><div class="hw-editor-tip warn"><div class="title">注意</div><div class="content"> <p id="ZH-CN_TOPIC_0000002084338673__p386990246144659">enum 和 interface 中仅支持定义成员函数,不支持定义成员变量。</p> </div></div></div> <p id="ZH-CN_TOPIC_0000002084338673__p321746630144659">例如在以下程序中,我们在顶层作用域定义了全局函数 a 和自定义类型 A,在函数 a 中定义了局部变量 b 和局部函数 c,在自定义类型 A 中定义了成员变量 b 和成员函数 c。</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002084338673__screen1503929990144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-comment">// example.cj</span></li><li><span class="hljs-keyword">func</span> <span class="hljs-title function_">a</span>() {</li><li> <span class="hljs-keyword">let</span> <span class="hljs-variable">b</span> = <span class="hljs-number">2023</span></li><li> <span class="hljs-keyword">func</span> <span class="hljs-title function_">c</span>() {</li><li> <span class="hljs-title function_">println</span>(<span class="hljs-variable">b</span>)</li><li> }</li><li> <span class="hljs-title function_">c</span>()</li><li>}</li><li> </li><li><span class="hljs-keyword">class</span> <span class="hljs-title class_">A</span> {</li><li> <span class="hljs-keyword">let</span> <span class="hljs-variable">b</span> = <span class="hljs-number">2024</span></li><li> <span class="hljs-keyword">public</span> <span class="hljs-keyword">func</span> <span class="hljs-title function_">c</span>() {</li><li> <span class="hljs-title function_">println</span>(<span class="hljs-variable">b</span>)</li><li> }</li><li>}</li><li> </li><li><span class="hljs-keyword">main</span>() {</li><li> <span class="hljs-title function_">a</span>()</li><li> <span class="hljs-title function_">A</span>().<span class="hljs-title function_">c</span>()</li><li>}</li></ol></pre> <p id="ZH-CN_TOPIC_0000002084338673__p1015838639144659">运行以上程序,将输出:</p> <pre class="text prettyprint linenums hljs language-plaintext" id="ZH-CN_TOPIC_0000002084338673__screen1690306334144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li>2023</li><li>2024</li></ol></pre> <div class="tiledSection"><h2 id="变量">变量<i class="anchorIcon" anchorid="变量" tips="复制节点链接"></i></h2><p id="ZH-CN_TOPIC_0000002084338673__p1865433950144659">在仓颉编程语言中,一个变量由对应的变量名、数据(值)和若干属性构成,开发者通过变量名访问变量对应的数据,但访问操作需要遵从相关属性的约束(如数据类型、可变性和可见性等)。</p> <p id="ZH-CN_TOPIC_0000002084338673__p1485872232144659">变量定义的具体形式为:</p> <pre class="text prettyprint linenums hljs language-plaintext" id="ZH-CN_TOPIC_0000002084338673__screen1432370376144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li>修饰符 变量名: 变量类型 = 初始值</li></ol></pre> <p id="ZH-CN_TOPIC_0000002084338673__p236738143144659">其中<strong>修饰符</strong>用于设置变量的各类属性,可以有一个或多个,常用的修饰符包括:</p> <ul id="ZH-CN_TOPIC_0000002084338673__ul257852162144659"><li id="li1595925108144659">可变性修饰符:let 与 var,分别对应不可变和可变属性,可变性决定了变量被初始化后其值还能否改变,仓颉变量也由此分为不可变变量和可变变量两类。</li><li id="li475858322144659">可见性修饰符:private 与 public 等,影响全局变量和成员变量的可引用范围,详见后续章节的相关介绍。</li><li id="li691299831144659">静态性修饰符:static,影响成员变量的存储和引用方式,详见后续章节的相关介绍。</li></ul> <p id="ZH-CN_TOPIC_0000002084338673__p798305787144659">在定义仓颉变量时,可变性修饰符是必要的,在此基础上,还可以根据需要添加其他修饰符。</p> <ul id="ZH-CN_TOPIC_0000002084338673__ul1950538081144659"><li id="li631601028144659"><strong>变量名</strong>应是一个合法的仓颉标识符。</li><li id="li395947169144659"><strong>变量类型</strong>指定了变量所持有数据的类型。当初始值具有明确类型时,可以省略变量类型标注,此时编译器可以自动推断出变量类型。</li><li id="li658345507144659"><strong>初始值</strong>是一个仓颉表达式,用于初始化变量,如果标注了变量类型,需要保证初始值类型和变量类型一致。在定义全局变量或静态成员变量时,必须指定初始值。在定义局部变量或实例成员变量时,可以省略初始值,但需要标注变量类型,同时要在此变量被引用前完成初始化,否则编译会报错。</li></ul> <p id="ZH-CN_TOPIC_0000002084338673__p94681685144659">例如,下列程序定义了两个 Int64 类型的不可变变量 a 和可变变量 b,随后修改了变量 b 的值,并调用 println 函数打印 a 与 b 的值。</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002084338673__screen1879358240144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">main</span>() {</li><li> <span class="hljs-keyword">let</span> <span class="hljs-variable">a</span>: <span class="hljs-keyword">Int64</span> = <span class="hljs-number">20</span></li><li> <span class="hljs-keyword">var</span> <span class="hljs-variable">b</span>: <span class="hljs-keyword">Int64</span> = <span class="hljs-number">12</span></li><li> <span class="hljs-variable">b</span> = <span class="hljs-number">23</span></li><li> <span class="hljs-title function_">println</span>(<span class="hljs-string">"<span class="hljs-subst">${<span class="hljs-variable">a</span>}</span><span class="hljs-subst">${<span class="hljs-variable">b</span>}</span>"</span>)</li><li>}</li></ol></pre> <p id="ZH-CN_TOPIC_0000002084338673__p184976380144659">编译运行此程序,将输出:</p> <pre class="text prettyprint linenums hljs language-plaintext" id="ZH-CN_TOPIC_0000002084338673__screen992567970144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li>2023</li></ol></pre> <p id="ZH-CN_TOPIC_0000002084338673__p1761681910144659">如果尝试修改不可变变量,编译时会报错,例如:</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002084338673__screen1095369121144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">main</span>() {</li><li> <span class="hljs-keyword">let</span> <span class="hljs-variable">pi</span>: <span class="hljs-keyword">Float64</span> = <span class="hljs-number">3.14159</span></li><li> <span class="hljs-variable">pi</span> = <span class="hljs-number">2.71828</span> <span class="hljs-comment">// Error, cannot assign to immutable value</span></li><li>}</li></ol></pre> <p id="ZH-CN_TOPIC_0000002084338673__p376368658144659">当初始值具有明确类型时,可以省略变量类型标注,例如:</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002084338673__screen1845198701144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">main</span>() {</li><li> <span class="hljs-keyword">let</span> <span class="hljs-variable">a</span>: <span class="hljs-keyword">Int64</span> = <span class="hljs-number">2023</span></li><li> <span class="hljs-keyword">let</span> <span class="hljs-variable">b</span> = <span class="hljs-variable">a</span></li><li> <span class="hljs-title function_">println</span>(<span class="hljs-string">"a - b = <span class="hljs-subst">${<span class="hljs-variable">a</span> - <span class="hljs-variable">b</span>}</span>"</span>)</li><li>}</li></ol></pre> <p id="ZH-CN_TOPIC_0000002084338673__p1413122749144659">其中变量 b 的类型可以由其初值 a 的类型自动推断为 Int64,所以此程序也可以被正常编译和运行,将输出:</p> <pre class="text prettyprint linenums hljs language-plaintext" id="ZH-CN_TOPIC_0000002084338673__screen1388919445144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li>a - b = 0</li></ol></pre> <p id="ZH-CN_TOPIC_0000002084338673__p1129748323144659">在定义局部变量时,可以不进行初始化,但一定要在变量被引用前赋予初值,例如:</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002084338673__screen135056002144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">main</span>() {</li><li> <span class="hljs-keyword">let</span> <span class="hljs-variable">text</span>: <span class="hljs-title class_">String</span></li><li> <span class="hljs-variable">text</span> = <span class="hljs-string">"仓颉造字"</span></li><li> <span class="hljs-title function_">println</span>(<span class="hljs-variable">text</span>)</li><li>}</li></ol></pre> <p id="ZH-CN_TOPIC_0000002084338673__p2069506074144659">编译运行此程序,将输出:</p> <pre class="text prettyprint linenums hljs language-plaintext" id="ZH-CN_TOPIC_0000002084338673__screen563428674144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li>仓颉造字</li></ol></pre> <p id="ZH-CN_TOPIC_0000002084338673__p1106005084144659">在定义全局变量和静态成员变量时必须初始化,否则编译会报错,例如:</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002084338673__screen2140722309144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-comment">// example.cj</span></li><li><span class="hljs-keyword">let</span> <span class="hljs-variable">global</span>: <span class="hljs-keyword">Int64</span> <span class="hljs-comment">// Error, variable in top-level scope must be initialized</span></li></ol></pre> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002084338673__screen1499282186144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-comment">// example.cj</span></li><li><span class="hljs-keyword">class</span> <span class="hljs-title class_">Player</span> {</li><li> <span class="hljs-keyword">static</span> <span class="hljs-keyword">let</span> <span class="hljs-variable">score</span>: <span class="hljs-keyword">Int32</span> <span class="hljs-comment">// Error, static variable 'score' needs to be initialized when declaring</span></li><li>}</li></ol></pre> </div> <div class="tiledSection"><h3 id="值类型和引用类型变量" class="firsth2">值类型和引用类型变量<i class="anchorIcon" anchorid="值类型和引用类型变量" tips="复制节点链接"></i></h3><p id="ZH-CN_TOPIC_0000002084338673__p1668916068144659">程序在运行阶段,只有指令流转和数据变换,仓颉程序中的各种标识符已不复存在。由此可见,编译器使用了一些机制,将这些名字和编程所取用的数据实体/存储空间绑定起来。</p> <p id="ZH-CN_TOPIC_0000002084338673__p460197019144659">从编译器实现层面看,任何变量总会关联一个值(一般是通过内存地址/寄存器关联),只是在使用时,对有些变量,我们将直接取用这个值本身,这被称为<strong>值类型变量</strong>,而对另一些变量,我们把这个值作为索引、取用这个索引指示的数据,这被称为<strong>引用类型变量</strong>。值类型变量通常在线程栈上分配,每个变量都有自己的数据副本;引用类型变量通常在进程堆中分配,多个变量可引用同一数据对象,对一个变量执行的操作可能会影响其他变量。</p> <p id="ZH-CN_TOPIC_0000002084338673__p956628100144659">从语言层面看,值类型变量对它所绑定的数据/存储空间是独占的,而引用类型变量所绑定的数据/存储空间可以和其他引用类型变量共享。</p> <p id="ZH-CN_TOPIC_0000002084338673__p1625288853144659">基于上述原理,在使用值类型变量和引用类型变量时,会存在一些行为差异,以下几点值得注意:</p> <ol id="ZH-CN_TOPIC_0000002084338673__ol373338302144659"><li id="li1599641833144659">在给值类型变量赋值时,一般会产生拷贝操作,且原来绑定的数据/存储空间被覆写。在给引用类型变量赋值时,只是改变了引用关系,原来绑定的数据/存储空间不会被覆写。</li><li id="li344125182144659">用 let 定义的变量,要求变量被初始化后都不能再赋值。对于引用类型,这只是限定了引用关系不可改变,但是所引用的数据是可以被修改的。</li></ol> <p id="ZH-CN_TOPIC_0000002084338673__p687598062144659">在仓颉编程语言中,class 和 Array 等类型属于引用类型,其他基础数据类型和 struct 等类型属于值类型。</p> <p id="ZH-CN_TOPIC_0000002084338673__p288064828144659">例如,以下程序演示了 struct 和 class 类型变量的行为差异:</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002084338673__screen1222516224144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">struct</span> <span class="hljs-title class_">Copy</span> {</li><li> <span class="hljs-keyword">var</span> <span class="hljs-variable">data</span> = <span class="hljs-number">2012</span></li><li>}</li><li> </li><li><span class="hljs-keyword">class</span> <span class="hljs-title class_">Share</span> {</li><li> <span class="hljs-keyword">var</span> <span class="hljs-variable">data</span> = <span class="hljs-number">2012</span></li><li>}</li><li> </li><li><span class="hljs-keyword">main</span>() {</li><li> <span class="hljs-keyword">let</span> <span class="hljs-variable">c1</span> = <span class="hljs-title function_">Copy</span>()</li><li> <span class="hljs-keyword">var</span> <span class="hljs-variable">c2</span> = <span class="hljs-variable">c1</span></li><li> <span class="hljs-variable">c2</span>.<span class="hljs-variable">data</span> = <span class="hljs-number">2023</span></li><li> <span class="hljs-title function_">println</span>(<span class="hljs-string">"<span class="hljs-subst">${<span class="hljs-variable">c1</span>.<span class="hljs-variable">data</span>}</span>, <span class="hljs-subst">${<span class="hljs-variable">c2</span>.<span class="hljs-variable">data</span>}</span>"</span>)</li><li> </li><li> <span class="hljs-keyword">let</span> <span class="hljs-variable">s1</span> = <span class="hljs-title function_">Share</span>()</li><li> <span class="hljs-keyword">let</span> <span class="hljs-variable">s2</span> = <span class="hljs-variable">s1</span></li><li> <span class="hljs-variable">s2</span>.<span class="hljs-variable">data</span> = <span class="hljs-number">2023</span></li><li> <span class="hljs-title function_">println</span>(<span class="hljs-string">"<span class="hljs-subst">${<span class="hljs-variable">s1</span>.<span class="hljs-variable">data</span>}</span>, <span class="hljs-subst">${<span class="hljs-variable">s2</span>.<span class="hljs-variable">data</span>}</span>"</span>)</li><li>}</li></ol></pre> <p id="ZH-CN_TOPIC_0000002084338673__p772082844144659">运行以上程序,将输出:</p> <pre class="text prettyprint linenums hljs language-plaintext" id="ZH-CN_TOPIC_0000002084338673__screen1110803297144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li>2012, 2023</li><li>2023, 2023</li></ol></pre> <p id="ZH-CN_TOPIC_0000002084338673__p721640456144659">由此可以看出,对于值类型的 Copy 类型变量,在赋值时总是获取 Copy 实例的拷贝,如 c2 = c1,随后对 c2 成员的修改并不影响 c1。对于引用类型的 Share 类型变量,在赋值时将建立变量和实例之间的引用关系,如 s2 = s1,随后对 s2 成员的修改会影响 s1。</p> <p id="ZH-CN_TOPIC_0000002084338673__p1261529070144659">如果将以上程序中的 var c2 = c1 改成 let c2 = c1,则编译会报错,例如:</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002084338673__screen1319132003144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">struct</span> <span class="hljs-title class_">Copy</span> {</li><li> <span class="hljs-keyword">var</span> <span class="hljs-variable">data</span> = <span class="hljs-number">2012</span></li><li>}</li><li> </li><li><span class="hljs-keyword">main</span>() {</li><li> <span class="hljs-keyword">let</span> <span class="hljs-variable">c1</span> = <span class="hljs-title function_">Copy</span>()</li><li> <span class="hljs-keyword">let</span> <span class="hljs-variable">c2</span> = <span class="hljs-variable">c1</span></li><li> <span class="hljs-variable">c2</span>.<span class="hljs-variable">data</span> = <span class="hljs-number">2023</span> <span class="hljs-comment">// Error, cannot assign to immutable value</span></li><li>}</li></ol></pre> </div> <div class="tiledSection"><h2 id="作用域">作用域<i class="anchorIcon" anchorid="作用域" tips="复制节点链接"></i></h2><p id="ZH-CN_TOPIC_0000002084338673__p25448862144659">在前文中,我们初步介绍了如何给仓颉程序元素命名,实际上,除了变量,我们还可以给函数和自定义类型等命名,在程序中将使用这些名字访问对应的程序元素。</p> <p id="ZH-CN_TOPIC_0000002084338673__p5263084144659">但在实际应用中,需要考虑一些特殊情况:</p> <ul id="ZH-CN_TOPIC_0000002084338673__ul747760183144659"><li id="li809426535144659">当程序规模较大时,那些简短的名字很容易重复,即产生命名冲突。</li><li id="li576007339144659">结合运行时考虑,在有些代码片段中,另一些程序元素是无效的,对它们的引用会导致运行时错误。</li><li id="li1534911142144659">在某些逻辑构造中,为了表达元素之间的包含关系,不应通过名字直接访问子元素,而是要通过其父元素名间接访问。</li></ul> <p id="ZH-CN_TOPIC_0000002084338673__p231793089144659">为了应对这些问题,现代编程语言引入了“作用域”的概念及设计,将名字和程序元素的绑定关系限制在一定范围里。不同作用域之间可以是并列或无关的,也可以是嵌套或包含关系。一个作用域将明确我们能用哪些名字访问哪些程序元素,具体规则是:</p> <ol id="ZH-CN_TOPIC_0000002084338673__ol1556578084144659"><li id="li629002885144659">当前作用域中定义的程序元素与名字的绑定关系,在当前作用域和其内层作用域中是有效的,可以通过此名字直接访问对应的程序元素。</li><li id="li1913379380144659">内层作用域中定义的程序元素与名字的绑定关系,在外层作用域中无效。</li><li id="li702956388144659">内层作用域可以使用外层作用域中的名字重新定义绑定关系,根据规则 1,此时内层作用域中的命名相当于遮盖了外层作用域中的同名定义,对此我们称内层作用域的级别比外层作用域的级别高。</li></ol> <p id="ZH-CN_TOPIC_0000002084338673__p169592879144659">在仓颉编程语言中,用一对大括号“{}”包围一段仓颉代码,即构造了一个新的作用域,其中可以继续使用大括号“{}”包围仓颉代码,由此产生了嵌套作用域,这些作用域均服从上述规则。特别的,在一个仓颉源文件中,不被任何大括号“{}”包围的代码,它们所属的作用域被称为“顶层作用域”,即当前文件中“最外层”的作用域,按上述规则,其作用域级别最低。</p> <div><div class="hw-editor-tip warn"><div class="title">注意</div><div class="content"> <p id="ZH-CN_TOPIC_0000002084338673__p1877271688144659">用大括号“{}”包围代码构造作用域时,其中不限于使用表达式,还可以定义函数和自定义类型等。</p> </div></div></div> <p id="ZH-CN_TOPIC_0000002084338673__p356422113144659">例如在以下名为 test.cj 的仓颉源文件里,在顶层作用域中定义了名字 element,它和字符串“仓颉”绑定,而 main 和 if 引导的代码块中也定义了名字 element,分别对应整数 9 和整数 2023。由上述作用域规则,在第 4 行,element 的值为“仓颉”,在第 8 行,element 的值为 2023,在第 10 行,element 的值为 9。</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002084338673__screen3315180144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-comment">// test.cj</span></li><li><span class="hljs-keyword">let</span> <span class="hljs-variable">element</span> = <span class="hljs-string">"仓颉"</span></li><li><span class="hljs-keyword">main</span>() {</li><li> <span class="hljs-title function_">println</span>(<span class="hljs-variable">element</span>)</li><li> <span class="hljs-keyword">let</span> <span class="hljs-variable">element</span> = <span class="hljs-number">9</span></li><li> <span class="hljs-keyword">if</span> (<span class="hljs-variable">element</span> > <span class="hljs-number">0</span>) {</li><li> <span class="hljs-keyword">let</span> <span class="hljs-variable">element</span> = <span class="hljs-number">2023</span></li><li> <span class="hljs-title function_">println</span>(<span class="hljs-variable">element</span>)</li><li> }</li><li> <span class="hljs-title function_">println</span>(<span class="hljs-variable">element</span>)</li><li>}</li></ol></pre> <p id="ZH-CN_TOPIC_0000002084338673__p1286366902144659">运行以上程序,将输出:</p> <pre class="text prettyprint linenums hljs language-plaintext" id="ZH-CN_TOPIC_0000002084338673__screen1379505148144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li>仓颉</li><li>2023</li><li>9</li></ol></pre> </div> </div> <div></div></div> ## 三、表达式 <div _ngcontent-apy-c173="" class="markdown-body ng-star-inserted" style="position: relative;"> <div id="body710381958144659"><p id="ZH-CN_TOPIC_0000002048298032__p948132340144659">在一些传统编程语言中,一个表达式由一个或多个操作数(operand)通过零个或多个操作符(operator)组合而成,表达式总是隐含着一个计算过程,因此每个表达式都会有一个计算结果,对于只有操作数而没有操作符的表达式,其计算结果就是操作数自身,对于包含操作符的表达式,计算结果是对操作数执行操作符定义的计算而得到的值。在这种定义下的表达式也被称为算术运算表达式。操作符优先级请参见<a href="https://developer.huawei.com/consumer/cn/doc/cangjie-guides-V5/operator-V5">操作符</a>章节。</p> <p id="ZH-CN_TOPIC_0000002048298032__p1236242913144659">在仓颉编程语言中,简化并延伸了表达式的传统定义——凡是可求值的语言元素都是表达式。因此,仓颉不仅有传统的算术运算表达式,还有条件表达式、循环表达式和 try 表达式等,它们都可以被求值,并作为值去使用,如作为变量定义的初值和函数实参等。此外,因为仓颉是强类型的编程语言,所以仓颉表达式不仅可求值,还有确定的类型。</p> <p id="ZH-CN_TOPIC_0000002048298032__p880547999144659">仓颉编程语言的各种表达式将在后续章节中逐一介绍,本节介绍最常用的条件表达式、循环表达式以及部分控制转移表达式(break、continue)。</p> <p id="ZH-CN_TOPIC_0000002048298032__p915885529144659">任何一段程序的执行流程,只会涉及三种基本结构——顺序结构、分支结构和循环结构。实际上,分支结构和循环结构,是由某些指令控制当前顺序执行流产生跳转而得到的,它们让程序能够表达更复杂的逻辑,在仓颉中,这种用来控制执行流的语言元素就是条件表达式和循环表达式。</p> <p id="ZH-CN_TOPIC_0000002048298032__p234493190144659">在仓颉编程语言中,条件表达式分为 if 表达式和 if-let 表达式两种,它们的值与类型需要根据使用场景来确定。循环表达式有四种:for-in 表达式、while 表达式、do-while 表达式和 while-let 表达式,它们的类型都是 Unit、值为 ()。其中 if-let 表达式和 while-let 表达式都与模式匹配相关,请参见<a href="https://developer.huawei.com/consumer/cn/doc/cangjie-guides-V5/if_let-V5">if-let 表达式</a>和<a href="https://developer.huawei.com/consumer/cn/doc/cangjie-guides-V5/while_let-V5">while-let 表达式</a>章节,本节只介绍以上提及的其他几种表达式。</p> <p id="ZH-CN_TOPIC_0000002048298032__p1066444996144659">在仓颉程序中,由一对大括号“{}”包围起来的一组表达式,被称为“代码块”,它将作为程序的一个顺序执行流,其中的表达式将按编码顺序依次执行。如果代码块中有至少一个表达式,规定此代码块的值与类型等于其中最后一个表达式的值与类型,如果代码块中没有表达式,规定这种空代码块的类型为 Unit、值为 ()。</p> <div><div class="hw-editor-tip warn"><div class="title">注意</div><div class="content"> <p id="ZH-CN_TOPIC_0000002048298032__p793041314144659">代码块本身不是一个表达式,不能被单独使用,它将依附于函数、条件表达式和循环表达式等执行和求值。</p> </div></div></div> <div class="tiledSection"><h2 id="if-表达式">if 表达式<i class="anchorIcon" anchorid="if-表达式" tips="复制节点链接"></i></h2><p id="ZH-CN_TOPIC_0000002048298032__p843130343144659">if 表达式的基本形式为:</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002048298032__screen590971062144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">if</span> (<span class="hljs-variable">条件</span>) {</li><li> <span class="hljs-variable">分支</span> <span class="hljs-number">1</span></li><li>} <span class="hljs-keyword">else</span> {</li><li> <span class="hljs-variable">分支</span> <span class="hljs-number">2</span></li><li>}</li></ol></pre> <p id="ZH-CN_TOPIC_0000002048298032__p1765965193144659">其中“条件”是布尔类型表达式,“分支 1”和“分支 2”是两个代码块。if 表达式将按如下规则执行:</p> <ol id="ZH-CN_TOPIC_0000002048298032__ol504645253144659"><li id="li1495838228144659">计算“条件”表达式,如果值为 true 则转到第 2 步,值为 false 则转到第 3 步。</li><li id="li1199473776144659">执行“分支 1”,转到第 4 步。</li><li id="li95833244144659">执行“分支 2”,转到第 4 步。</li><li id="li2039923860144659">继续执行 if 表达式后面的代码。</li></ol> <p id="ZH-CN_TOPIC_0000002048298032__p1532000016144659">在一些场景中,可能只关注条件成立时该做些什么,所以 else 和对应的代码块是允许省略的。</p> <p id="ZH-CN_TOPIC_0000002048298032__p1193403036144659">如下程序演示了 if 表达式的基本用法:</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002048298032__screen507045390144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">import</span> <span class="hljs-package">std.random.*</span></li><li> </li><li><span class="hljs-keyword">main</span>() {</li><li> <span class="hljs-keyword">let</span> <span class="hljs-variable">number</span>: <span class="hljs-keyword">Int8</span> = <span class="hljs-title function_">Random</span>().<span class="hljs-title function_">nextInt8</span>()</li><li> <span class="hljs-title function_">println</span>(<span class="hljs-variable">number</span>)</li><li> <span class="hljs-keyword">if</span> (<span class="hljs-variable">number</span> % <span class="hljs-number">2</span> == <span class="hljs-number">0</span>) {</li><li> <span class="hljs-title function_">println</span>(<span class="hljs-string">"偶数"</span>)</li><li> } <span class="hljs-keyword">else</span> {</li><li> <span class="hljs-title function_">println</span>(<span class="hljs-string">"奇数"</span>)</li><li> }</li><li>}</li></ol></pre> <p id="ZH-CN_TOPIC_0000002048298032__p281423774144659">在这段程序中,使用仓颉标准库的 random 包生成了一个随机整数,然后使用 if 表达式判断这个整数是否能被 2 整除,并在不同的条件分支中打印“偶数”或“奇数”。</p> <p id="ZH-CN_TOPIC_0000002048298032__p204665184144659">仓颉编程语言是强类型的,if 表达式的条件只能是布尔类型,不能使用整数或浮点数等类型,和 C 语言等不同,仓颉不以条件取值是否为 0 作为分支选择依据,例如以下程序将编译报错:</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002048298032__screen1243575702144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">main</span>() {</li><li> <span class="hljs-keyword">let</span> <span class="hljs-variable">number</span> = <span class="hljs-number">1</span></li><li> <span class="hljs-keyword">if</span> (<span class="hljs-variable">number</span>) { <span class="hljs-comment">// Error, mismatched types</span></li><li> <span class="hljs-title function_">println</span>(<span class="hljs-string">"非零数"</span>)</li><li> }</li><li>}</li></ol></pre> <p id="ZH-CN_TOPIC_0000002048298032__p1126615056144659">在许多场景中,当一个条件不成立时,可能还要判断另一个或多个条件、再执行对应的动作,仓颉允许在 else 之后跟随新的 if 表达式,由此支持多级条件判断和分支执行,例如:</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002048298032__screen127389584144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">import</span> <span class="hljs-package">std.random.*</span></li><li> </li><li><span class="hljs-keyword">main</span>() {</li><li> <span class="hljs-keyword">let</span> <span class="hljs-variable">speed</span> = <span class="hljs-title function_">Random</span>().<span class="hljs-title function_">nextFloat64</span>() * <span class="hljs-number">20.0</span></li><li> <span class="hljs-title function_">println</span>(<span class="hljs-string">"<span class="hljs-subst">${<span class="hljs-variable">speed</span>}</span> km/s"</span>)</li><li> <span class="hljs-keyword">if</span> (<span class="hljs-variable">speed</span> > <span class="hljs-number">16.7</span>) {</li><li> <span class="hljs-title function_">println</span>(<span class="hljs-string">"第三宇宙速度,鹊桥相会"</span>)</li><li> } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (<span class="hljs-variable">speed</span> > <span class="hljs-number">11.2</span>) {</li><li> <span class="hljs-title function_">println</span>(<span class="hljs-string">"第二宇宙速度,嫦娥奔月"</span>)</li><li> } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (<span class="hljs-variable">speed</span> > <span class="hljs-number">7.9</span>) {</li><li> <span class="hljs-title function_">println</span>(<span class="hljs-string">"第一宇宙速度,腾云驾雾"</span>)</li><li> } <span class="hljs-keyword">else</span> {</li><li> <span class="hljs-title function_">println</span>(<span class="hljs-string">"脚踏实地,仰望星空"</span>)</li><li> }</li><li>}</li></ol></pre> <p id="ZH-CN_TOPIC_0000002048298032__p1075273432144659">if 表达式的值与类型,需要根据使用形式与场景来确定:</p> <ul id="ZH-CN_TOPIC_0000002048298032__ul761225536144659"><li id="li1767419878144659"><p id="ZH-CN_TOPIC_0000002048298032__p889179678144659">当含 else 分支的 if 表达式被求值时,需要根据求值上下文确定 if 表达式的类型:</p> <ul id="ZH-CN_TOPIC_0000002048298032__ul1127187112144659"><li id="li217468828144659">如果上下文明确要求值类型为 T,则 if 表达式各分支代码块的类型必须是 T 的子类型,这时 if 表达式的类型被确定为 T,如果不满足子类型约束,编译会报错。</li><li id="li625821084144659">如果上下文没有明确的类型要求,则 if 表达式的类型是其各分支代码块类型的最小公共父类型,如果最小公共父类型不存在,编译会报错。</li></ul> <p id="ZH-CN_TOPIC_0000002048298032__p1153640697144659">如果编译通过,则 if 表达式的值就是所执行分支代码块的值。</p> </li><li id="li1401327241144659"><p id="ZH-CN_TOPIC_0000002048298032__p316932863144659">如果含 else 分支的 if 表达式没有被求值,在这种场景里,开发者一般只想在不同分支里做不同操作,不会关注各分支最后一个表达式的值与类型,为了不让上述类型检查规则影响这一思维习惯,仓颉规定这种场景下的 if 表达式类型为 Unit、值为 (),且各分支不参与上述类型检查。</p> </li><li id="li122938986144659"><p id="ZH-CN_TOPIC_0000002048298032__p1068920465144659">对于不含 else 分支的 if 表达式,由于 if 分支也可能不被执行,所以规定这类 if 表达式的类型为 Unit、值为 ()。</p> </li></ul> <p id="ZH-CN_TOPIC_0000002048298032__p1697362294144659">例如,以下程序基于 if 表达式求值,模拟一次简单的模数转换过程:</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002048298032__screen901299443144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">main</span>() {</li><li> <span class="hljs-keyword">let</span> <span class="hljs-variable">zero</span>: <span class="hljs-keyword">Int8</span> = <span class="hljs-number">0</span></li><li> <span class="hljs-keyword">let</span> <span class="hljs-variable">one</span>: <span class="hljs-keyword">Int8</span> = <span class="hljs-number">1</span></li><li> <span class="hljs-keyword">let</span> <span class="hljs-variable">voltage</span> = <span class="hljs-number">5.0</span></li><li> <span class="hljs-keyword">let</span> <span class="hljs-variable">bit</span> = <span class="hljs-keyword">if</span> (<span class="hljs-variable">voltage</span> < <span class="hljs-number">2.5</span>) {</li><li> <span class="hljs-variable">zero</span></li><li> } <span class="hljs-keyword">else</span> {</li><li> <span class="hljs-variable">one</span></li><li> }</li><li>}</li></ol></pre> <p id="ZH-CN_TOPIC_0000002048298032__p2101395159144659">在以上程序中,if 表达式作为变量定义的初值使用,由于变量 bit 没有被标注类型、需要从初值中推导,所以 if 表达式的类型取为两个分支代码块类型的最小公共父类型,根据前文对“代码块”的介绍,可知两个分支代码块类型都是 Int8,所以 if 表达式的类型被确定为 Int8,其值为所执行分支即 else 分支代码块的值,所以变量 bit 的类型为 Int8、值为 1。</p> </div> <div class="tiledSection"><h2 id="while-表达式">while 表达式<i class="anchorIcon" anchorid="while-表达式" tips="复制节点链接"></i></h2><p id="ZH-CN_TOPIC_0000002048298032__p1457015872144659">while 表达式的基本形式为:</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002048298032__screen1534079399144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">while</span> (<span class="hljs-variable">条件</span>) {</li><li> <span class="hljs-variable">循环体</span></li><li>}</li></ol></pre> <p id="ZH-CN_TOPIC_0000002048298032__p785817898144659">其中“条件”是布尔类型表达式,“循环体”是一个代码块。while 表达式将按如下规则执行:</p> <ol id="ZH-CN_TOPIC_0000002048298032__ol1307142259144659"><li id="li687536995144659">计算“条件”表达式,如果值为 true 则转第 2 步,值为 false 转第 3 步。</li><li id="li2095760191144659">执行“循环体”,转第 1 步。</li><li id="li1729603778144659">结束循环,继续执行 while 表达式后面的代码。</li></ol> <p id="ZH-CN_TOPIC_0000002048298032__p1756619032144659">例如,以下程序使用 while 表达式,基于二分法,近似计算数字 2 的平方根:</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002048298032__screen601557577144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">main</span>() {</li><li> <span class="hljs-keyword">var</span> <span class="hljs-variable">root</span> = <span class="hljs-number">0.0</span></li><li> <span class="hljs-keyword">var</span> <span class="hljs-variable">min</span> = <span class="hljs-number">1.0</span></li><li> <span class="hljs-keyword">var</span> <span class="hljs-variable">max</span> = <span class="hljs-number">2.0</span></li><li> <span class="hljs-keyword">var</span> <span class="hljs-variable">error</span> = <span class="hljs-number">1.0</span></li><li> <span class="hljs-keyword">let</span> <span class="hljs-variable">tolerance</span> = <span class="hljs-number">0.1</span> ** <span class="hljs-number">10</span></li><li> </li><li> <span class="hljs-keyword">while</span> (<span class="hljs-variable">error</span> ** <span class="hljs-number">2</span> > <span class="hljs-variable">tolerance</span>) {</li><li> <span class="hljs-variable">root</span> = (<span class="hljs-variable">min</span> + <span class="hljs-variable">max</span>) / <span class="hljs-number">2.0</span></li><li> <span class="hljs-variable">error</span> = <span class="hljs-variable">root</span> ** <span class="hljs-number">2</span> - <span class="hljs-number">2.0</span></li><li> <span class="hljs-keyword">if</span> (<span class="hljs-variable">error</span> > <span class="hljs-number">0.0</span>) {</li><li> <span class="hljs-variable">max</span> = <span class="hljs-variable">root</span></li><li> } <span class="hljs-keyword">else</span> {</li><li> <span class="hljs-variable">min</span> = <span class="hljs-variable">root</span></li><li> }</li><li> }</li><li> <span class="hljs-title function_">println</span>(<span class="hljs-string">"2 的平方根约等于:<span class="hljs-subst">${<span class="hljs-variable">root</span>}</span>"</span>)</li><li>}</li></ol></pre> <p id="ZH-CN_TOPIC_0000002048298032__p1755513089144659">运行以上程序,将输出:</p> <pre class="text prettyprint linenums hljs language-plaintext" id="ZH-CN_TOPIC_0000002048298032__screen600521116144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li>2 的平方根约等于:1.414215</li></ol></pre> </div> <div class="tiledSection"><h2 id="do-while-表达式">do-while 表达式<i class="anchorIcon" anchorid="do-while-表达式" tips="复制节点链接"></i></h2><p id="ZH-CN_TOPIC_0000002048298032__p1634198940144659">do-while 表达式的基本形式为:</p> <pre class="screen prettyprint linenums hljs language-bash" id="ZH-CN_TOPIC_0000002048298032__screen1976208870144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">do</span> {</li><li> 循环体</li><li>} <span class="hljs-keyword">while</span> (条件)</li></ol></pre> <p id="ZH-CN_TOPIC_0000002048298032__p847131661144659">其中“条件”是布尔类型表达式,“循环体”是一个代码块。do-while 表达式将按如下规则执行:</p> <ol id="ZH-CN_TOPIC_0000002048298032__ol1185070310144659"><li id="li1207356337144659">执行“循环体”,转第 2 步。</li><li id="li1001050830144659">计算“条件”表达式,如果值为 true 则转第 1 步,值为 false 转第 3 步。</li><li id="li805215608144659">结束循环,继续执行 do-while 表达式后面的代码。</li></ol> <p id="ZH-CN_TOPIC_0000002048298032__p1083279550144659">例如,以下程序使用 do-while 表达式,基于蒙特卡洛算法,近似计算圆周率的值:</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002048298032__screen561847639144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">import</span> <span class="hljs-package">std.random.*</span></li><li> </li><li><span class="hljs-keyword">main</span>() {</li><li> <span class="hljs-keyword">let</span> <span class="hljs-variable">random</span> = <span class="hljs-title function_">Random</span>()</li><li> <span class="hljs-keyword">var</span> <span class="hljs-variable">totalPoints</span> = <span class="hljs-number">0</span></li><li> <span class="hljs-keyword">var</span> <span class="hljs-variable">hitPoints</span> = <span class="hljs-number">0</span></li><li> </li><li> <span class="hljs-keyword">do</span> {</li><li> <span class="hljs-comment">// 在 ((0, 0), (1, 1)) 这个正方形中随机取点</span></li><li> <span class="hljs-keyword">let</span> <span class="hljs-variable">x</span> = <span class="hljs-variable">random</span>.<span class="hljs-title function_">nextFloat64</span>()</li><li> <span class="hljs-keyword">let</span> <span class="hljs-variable">y</span> = <span class="hljs-variable">random</span>.<span class="hljs-title function_">nextFloat64</span>()</li><li> <span class="hljs-comment">// 判断是否落在正方形内接圆里</span></li><li> <span class="hljs-keyword">if</span> ((<span class="hljs-variable">x</span> - <span class="hljs-number">0.5</span>) ** <span class="hljs-number">2</span> + (<span class="hljs-variable">y</span> - <span class="hljs-number">0.5</span>) ** <span class="hljs-number">2</span> < <span class="hljs-number">0.25</span>) {</li><li> <span class="hljs-variable">hitPoints</span>++</li><li> }</li><li> <span class="hljs-variable">totalPoints</span>++</li><li> } <span class="hljs-keyword">while</span> (<span class="hljs-variable">totalPoints</span> < <span class="hljs-number">1000000</span>)</li><li> </li><li> <span class="hljs-keyword">let</span> <span class="hljs-variable">pi</span> = <span class="hljs-number">4.0</span> * <span class="hljs-keyword">Float64</span>(<span class="hljs-variable">hitPoints</span>) / <span class="hljs-keyword">Float64</span>(<span class="hljs-variable">totalPoints</span>)</li><li> <span class="hljs-title function_">println</span>(<span class="hljs-string">"圆周率近似值为:<span class="hljs-subst">${<span class="hljs-variable">pi</span>}</span>"</span>)</li><li>}</li></ol></pre> <p id="ZH-CN_TOPIC_0000002048298032__p1470423130144659">运行以上程序,将输出:</p> <pre class="text prettyprint linenums hljs language-plaintext" id="ZH-CN_TOPIC_0000002048298032__screen1520810031144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li>圆周率近似值为:3.141872</li></ol></pre> <div><div class="hw-editor-tip info"><div class="title">说明</div><div class="content"> <p id="ZH-CN_TOPIC_0000002048298032__p2093554980144659">由于算法涉及随机数,所以每次运行程序输出的数值可能都不同,但都会约等于 3.14。</p> </div></div></div> </div> <div class="tiledSection"><h2 id="for-in-表达式">for-in 表达式<i class="anchorIcon" anchorid="for-in-表达式" tips="复制节点链接"></i></h2><p id="ZH-CN_TOPIC_0000002048298032__p2040770368144659">for-in 表达式可以遍历那些扩展了迭代器接口 Iterable<T> 的类型实例。for-in 表达式的基本形式为:</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002048298032__screen713474207144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">for</span> (<span class="hljs-variable">迭代变量</span> <span class="hljs-keyword">in</span> <span class="hljs-variable">序列</span>) {</li><li> <span class="hljs-variable">循环体</span></li><li>}</li></ol></pre> <p id="ZH-CN_TOPIC_0000002048298032__p1281498682144659">其中“循环体”是一个代码块。“迭代变量”是单个标识符或由多个标识符构成的元组,用于绑定每轮遍历中由迭代器指向的数据,可以作为“循环体”中的局部变量使用。“序列”是一个表达式,它只会被计算一次,遍历是针对此表达式的值进行的,其类型必须扩展了迭代器接口 Iterable<T>。for-in 表达式将按如下规则执行:</p> <ol id="ZH-CN_TOPIC_0000002048298032__ol1228922822144659"><li id="li1875130632144659">计算“序列”表达式,将其值作为遍历对象,并初始化遍历对象的迭代器。</li><li id="li1136153689144659">更新迭代器,如果迭代器终止,转第 4 步,否则转第 3 步。</li><li id="li197737329144659">将当前迭代器指向的数据与“迭代变量”绑定,并执行“循环体”,转第 2 步。</li><li id="li1813827183144659">结束循环,继续执行 for-in 表达式后面的代码。</li></ol> <div><div class="hw-editor-tip info"><div class="title">说明</div><div class="content"> <p id="ZH-CN_TOPIC_0000002048298032__p1390955638144659">仓颉内置的区间和数组等类型已经扩展了 Iterable<T> 接口。</p> </div></div></div> <p id="ZH-CN_TOPIC_0000002048298032__p370912593144659">例如,以下程序使用 for-in 表达式,遍历中国地支字符构成的数组 noumenonArray,输出农历 2024 年各月的干支纪法:</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002048298032__screen38443472144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">main</span>() {</li><li> <span class="hljs-keyword">let</span> <span class="hljs-variable">metaArray</span> = [<span class="hljs-variable">r</span><span class="hljs-string">'甲'</span>, <span class="hljs-variable">r</span><span class="hljs-string">'乙'</span>, <span class="hljs-variable">r</span><span class="hljs-string">'丙'</span>, <span class="hljs-variable">r</span><span class="hljs-string">'丁'</span>, <span class="hljs-variable">r</span><span class="hljs-string">'戊'</span>,</li><li> <span class="hljs-variable">r</span><span class="hljs-string">'己'</span>, <span class="hljs-variable">r</span><span class="hljs-string">'庚'</span>, <span class="hljs-variable">r</span><span class="hljs-string">'辛'</span>, <span class="hljs-variable">r</span><span class="hljs-string">'壬'</span>, <span class="hljs-variable">r</span><span class="hljs-string">'癸'</span>]</li><li> <span class="hljs-keyword">let</span> <span class="hljs-variable">noumenonArray</span> = [<span class="hljs-variable">r</span><span class="hljs-string">'寅'</span>, <span class="hljs-variable">r</span><span class="hljs-string">'卯'</span>, <span class="hljs-variable">r</span><span class="hljs-string">'辰'</span>, <span class="hljs-variable">r</span><span class="hljs-string">'巳'</span>, <span class="hljs-variable">r</span><span class="hljs-string">'午'</span>, <span class="hljs-variable">r</span><span class="hljs-string">'未'</span>,</li><li> <span class="hljs-variable">r</span><span class="hljs-string">'申'</span>, <span class="hljs-variable">r</span><span class="hljs-string">'酉'</span>, <span class="hljs-variable">r</span><span class="hljs-string">'戌'</span>, <span class="hljs-variable">r</span><span class="hljs-string">'亥'</span>, <span class="hljs-variable">r</span><span class="hljs-string">'子'</span>, <span class="hljs-variable">r</span><span class="hljs-string">'丑'</span>]</li><li> <span class="hljs-keyword">let</span> <span class="hljs-variable">year</span> = <span class="hljs-number">2024</span></li><li> <span class="hljs-comment">// 年份对应的天干索引</span></li><li> <span class="hljs-keyword">let</span> <span class="hljs-variable">metaOfYear</span> = ((<span class="hljs-variable">year</span> % <span class="hljs-number">10</span>) + <span class="hljs-number">10</span> - <span class="hljs-number">4</span>) % <span class="hljs-number">10</span></li><li> <span class="hljs-comment">// 此年首月对应的天干索引</span></li><li> <span class="hljs-keyword">var</span> <span class="hljs-variable">index</span> = (<span class="hljs-number">2</span> * <span class="hljs-variable">metaOfYear</span> + <span class="hljs-number">3</span>) % <span class="hljs-number">10</span> - <span class="hljs-number">1</span></li><li> <span class="hljs-title function_">println</span>(<span class="hljs-string">"农历 2024 年各月干支:"</span>)</li><li> <span class="hljs-keyword">for</span> (<span class="hljs-variable">noumenon</span> <span class="hljs-keyword">in</span> <span class="hljs-variable">noumenonArray</span>) {</li><li> <span class="hljs-title function_">print</span>(<span class="hljs-string">"<span class="hljs-subst">${<span class="hljs-variable">metaArray</span>[<span class="hljs-variable">index</span>]}</span><span class="hljs-subst">${<span class="hljs-variable">noumenon</span>}</span> "</span>)</li><li> <span class="hljs-variable">index</span> = (<span class="hljs-variable">index</span> + <span class="hljs-number">1</span>) % <span class="hljs-number">10</span></li><li> }</li><li>}</li></ol></pre> <p id="ZH-CN_TOPIC_0000002048298032__p1511660999144659">运行以上程序,将输出:</p> <pre class="text prettyprint linenums hljs language-plaintext" id="ZH-CN_TOPIC_0000002048298032__screen1167271743144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li>农历 2024 年各月干支:</li><li>丙寅 丁卯 戊辰 己巳 庚午 辛未 壬申 癸酉 甲戌 乙亥 丙子 丁丑</li></ol></pre> </div> <div class="tiledSection"><h3 id="遍历区间" class="firsth2">遍历区间<i class="anchorIcon" anchorid="遍历区间" tips="复制节点链接"></i></h3><p id="ZH-CN_TOPIC_0000002048298032__p170267754144659">for-in 表达式可以遍历区间类型实例,例如:</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002048298032__screen1983698453144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">main</span>() {</li><li> <span class="hljs-keyword">var</span> <span class="hljs-variable">sum</span> = <span class="hljs-number">0</span></li><li> <span class="hljs-keyword">for</span> (<span class="hljs-variable">i</span> <span class="hljs-keyword">in</span> <span class="hljs-number">1</span>..=<span class="hljs-number">100</span>) {</li><li> <span class="hljs-variable">sum</span> += <span class="hljs-variable">i</span></li><li> }</li><li> <span class="hljs-title function_">println</span>(<span class="hljs-variable">sum</span>)</li><li>}</li></ol></pre> <p id="ZH-CN_TOPIC_0000002048298032__p1011635928144659">运行以上程序,将输出:</p> <pre class="text prettyprint linenums hljs language-plaintext" id="ZH-CN_TOPIC_0000002048298032__screen1087806744144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li>5050</li></ol></pre> <p id="ZH-CN_TOPIC_0000002048298032__p1661768653144659">关于区间类型的详细内容,请参阅基本数据类型<a href="https://developer.huawei.com/consumer/cn/doc/cangjie-guides-V5/range-V5">区间类型</a>章节。</p> </div> <div class="tiledSection"><h3 id="遍历元组构成的序列">遍历元组构成的序列<i class="anchorIcon" anchorid="遍历元组构成的序列" tips="复制节点链接"></i></h3><p id="ZH-CN_TOPIC_0000002048298032__p1439234084144659">如果一个序列的元素是元组类型,则使用 for-in 表达式遍历时,“迭代变量”可以写成元组形式,以此实现对序列元素的解构,例如:</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002048298032__screen1563239601144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">main</span>() {</li><li> <span class="hljs-keyword">let</span> <span class="hljs-variable">array</span> = [(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>), (<span class="hljs-number">3</span>, <span class="hljs-number">4</span>), (<span class="hljs-number">5</span>, <span class="hljs-number">6</span>)]</li><li> <span class="hljs-keyword">for</span> ((<span class="hljs-variable">x</span>, <span class="hljs-variable">y</span>) <span class="hljs-keyword">in</span> <span class="hljs-variable">array</span>) {</li><li> <span class="hljs-title function_">println</span>(<span class="hljs-string">"<span class="hljs-subst">${<span class="hljs-variable">x</span>}</span>, <span class="hljs-subst">${<span class="hljs-variable">y</span>}</span>"</span>)</li><li> }</li><li>}</li></ol></pre> <p id="ZH-CN_TOPIC_0000002048298032__p339786277144659">运行以上程序,将输出:</p> <pre class="text prettyprint linenums hljs language-plaintext" id="ZH-CN_TOPIC_0000002048298032__screen699354544144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li>1, 2</li><li>3, 4</li><li>5, 6</li></ol></pre> </div> <div class="tiledSection"><h3 id="迭代变量不可修改">迭代变量不可修改<i class="anchorIcon" anchorid="迭代变量不可修改" tips="复制节点链接"></i></h3><p id="ZH-CN_TOPIC_0000002048298032__p1910309064144659">在 for-in 表达式的循环体中,不能修改迭代变量,例如以下程序在编译时会报错:</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002048298032__screen679945025144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">main</span>() {</li><li> <span class="hljs-keyword">for</span> (<span class="hljs-variable">i</span> <span class="hljs-keyword">in</span> <span class="hljs-number">0</span>..<span class="hljs-number">5</span>) {</li><li> <span class="hljs-variable">i</span> = <span class="hljs-variable">i</span> * <span class="hljs-number">10</span> <span class="hljs-comment">// Error, cannot assign to value which is an initialized 'let' constant</span></li><li> <span class="hljs-title function_">println</span>(<span class="hljs-variable">i</span>)</li><li> }</li><li>}</li></ol></pre> </div> <div class="tiledSection"><h3 id="使用通配符-_-代替迭代变量">使用通配符 _ 代替迭代变量<i class="anchorIcon" anchorid="使用通配符-_-代替迭代变量" tips="复制节点链接"></i></h3><p id="ZH-CN_TOPIC_0000002048298032__p1596123596144659">在一些应用场景中,只需要循环执行某些操作,但并不使用迭代变量,这时可以使用通配符 _ 代替迭代变量,例如:</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002048298032__screen1639311955144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">main</span>() {</li><li> <span class="hljs-keyword">var</span> <span class="hljs-variable">number</span> = <span class="hljs-number">2</span></li><li> <span class="hljs-keyword">for</span> (<span class="hljs-variable">_</span> <span class="hljs-keyword">in</span> <span class="hljs-number">0</span>..<span class="hljs-number">5</span>) {</li><li> <span class="hljs-variable">number</span> *= <span class="hljs-variable">number</span></li><li> }</li><li> <span class="hljs-title function_">println</span>(<span class="hljs-variable">number</span>)</li><li>}</li></ol></pre> <p id="ZH-CN_TOPIC_0000002048298032__p1686888914144659">运行以上程序,将输出:</p> <pre class="text prettyprint linenums hljs language-plaintext" id="ZH-CN_TOPIC_0000002048298032__screen22778296144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li>4294967296</li></ol></pre> <div><div class="hw-editor-tip warn"><div class="title">注意</div><div class="content"> <p id="ZH-CN_TOPIC_0000002048298032__p1215889716144659">在这种场景下,如果使用普通的标识符定义迭代变量,编译会输出“unused variable”告警,使用通配符 _ 则可以避免这一告警。</p> </div></div></div> </div> <div class="tiledSection"><h3 id="where-条件">where 条件<i class="anchorIcon" anchorid="where-条件" tips="复制节点链接"></i></h3><p id="ZH-CN_TOPIC_0000002048298032__p272800550144659">在部分循环遍历场景中,对于特定取值的迭代变量,可能需要直接跳过、进入下一轮循环,虽然可以使用 if 表达式和 continue 表达式在循环体中实现这一逻辑,但仓颉为此提供了更便捷的表达方式——可以在所遍历的“序列”之后用 where 关键字引导一个布尔表达式,这样在每次将进入循环体执行前,会先计算此表达式,如果值为 true 则执行循环体,反之直接进入下一轮循环。例如:</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002048298032__screen309184939144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">main</span>() {</li><li> <span class="hljs-keyword">for</span> (<span class="hljs-variable">i</span> <span class="hljs-keyword">in</span> <span class="hljs-number">0</span>..<span class="hljs-number">8</span> <span class="hljs-keyword">where</span> <span class="hljs-variable">i</span> % <span class="hljs-number">2</span> == <span class="hljs-number">1</span>) { <span class="hljs-comment">// i 为奇数才会执行循环体</span></li><li> <span class="hljs-title function_">println</span>(<span class="hljs-variable">i</span>)</li><li> }</li><li>}</li></ol></pre> <p id="ZH-CN_TOPIC_0000002048298032__p1786891345144659">运行以上程序,将输出:</p> <pre class="text prettyprint linenums hljs language-plaintext" id="ZH-CN_TOPIC_0000002048298032__screen1931890722144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li>1</li><li>3</li><li>5</li><li>7</li></ol></pre> </div> <div class="tiledSection"><h2 id="break-与-continue-表达式">break 与 continue 表达式<i class="anchorIcon" anchorid="break-与-continue-表达式" tips="复制节点链接"></i></h2><p id="ZH-CN_TOPIC_0000002048298032__p654216203144659">在循环结构的程序中,有时需要根据特定条件提前结束循环或跳过本轮循环,为此仓颉引入了 break 与 continue 表达式,它们可以出现在循环表达式的循环体中,break 用于终止当前循环表达式的执行、转去执行循环表达式之后的代码,continue 用于提前结束本轮循环、进入下一轮循环。break 与 continue 表达式的类型都是 Nothing。</p> <p id="ZH-CN_TOPIC_0000002048298032__p1129750861144659">例如,以下程序使用 for-in 表达式和 break 表达式,在给定的整数数组中,找到第一个能被 5 整除的数字:</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002048298032__screen290608689144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">main</span>() {</li><li> <span class="hljs-keyword">let</span> <span class="hljs-variable">numbers</span> = [<span class="hljs-number">12</span>, <span class="hljs-number">18</span>, <span class="hljs-number">25</span>, <span class="hljs-number">36</span>, <span class="hljs-number">49</span>, <span class="hljs-number">55</span>]</li><li> <span class="hljs-keyword">for</span> (<span class="hljs-variable">number</span> <span class="hljs-keyword">in</span> <span class="hljs-variable">numbers</span>) {</li><li> <span class="hljs-keyword">if</span> (<span class="hljs-variable">number</span> % <span class="hljs-number">5</span> == <span class="hljs-number">0</span>) {</li><li> <span class="hljs-title function_">println</span>(<span class="hljs-variable">number</span>)</li><li> <span class="hljs-keyword">break</span></li><li> }</li><li> }</li><li>}</li></ol></pre> <p id="ZH-CN_TOPIC_0000002048298032__p1726000975144659">当 for-in 迭代至 numbers 数组的第三个数 25 时,由于 25 可以被 5 整除,所以将执行 if 分支中的 println 和 break,break 将终止 for-in 循环,numbers中的后续数字不会被遍历到,因此运行以上程序,将输出:</p> <pre class="text prettyprint linenums hljs language-plaintext" id="ZH-CN_TOPIC_0000002048298032__screen792422070144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li>25</li></ol></pre> <p id="ZH-CN_TOPIC_0000002048298032__p219797624144659">以下程序使用 for-in 表达式和 continue 表达式,将给定整数数组中的奇数打印出来:</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002048298032__screen1013547238144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">main</span>() {</li><li> <span class="hljs-keyword">let</span> <span class="hljs-variable">numbers</span> = [<span class="hljs-number">12</span>, <span class="hljs-number">18</span>, <span class="hljs-number">25</span>, <span class="hljs-number">36</span>, <span class="hljs-number">49</span>, <span class="hljs-number">55</span>]</li><li> <span class="hljs-keyword">for</span> (<span class="hljs-variable">number</span> <span class="hljs-keyword">in</span> <span class="hljs-variable">numbers</span>) {</li><li> <span class="hljs-keyword">if</span> (<span class="hljs-variable">number</span> % <span class="hljs-number">2</span> == <span class="hljs-number">0</span>) {</li><li> <span class="hljs-keyword">continue</span></li><li> }</li><li> <span class="hljs-title function_">println</span>(<span class="hljs-variable">number</span>)</li><li> }</li><li>}</li></ol></pre> <p id="ZH-CN_TOPIC_0000002048298032__p1167544939144659">在循环迭代中,当 number 是偶数时,continue 将被执行,这会提前结束本轮循环、进入下一轮循环,println 不会被执行,因此运行以上程序,将输出:</p> <pre class="text prettyprint linenums hljs language-plaintext" id="ZH-CN_TOPIC_0000002048298032__screen527963978144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li>25</li><li>49</li><li>55</li></ol></pre> </div> </div> <div></div></div> ## 四、函数 <div _ngcontent-apy-c173="" class="markdown-body ng-star-inserted" style="position: relative;"> <div id="body174941617144659"><p id="ZH-CN_TOPIC_0000002084257249__p1807177453144659">仓颉使用关键字 func 来表示函数定义的开始,func 之后依次是函数名、参数列表、可选的函数返回值类型、函数体。其中,函数名可以是任意的合法标识符,参数列表定义在一对圆括号内(多个参数间使用逗号分隔),参数列表和函数返回值类型(如果存在)之间使用冒号分隔,函数体定义在一对花括号内。</p> <p id="ZH-CN_TOPIC_0000002084257249__p1702210698144659">函数定义举例:</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002084257249__screen1434788657144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">func</span> <span class="hljs-title function_">add</span>(<span class="hljs-variable">a</span>: <span class="hljs-keyword">Int64</span>, <span class="hljs-variable">b</span>: <span class="hljs-keyword">Int64</span>): <span class="hljs-keyword">Int64</span> {</li><li> <span class="hljs-keyword">return</span> <span class="hljs-variable">a</span> + <span class="hljs-variable">b</span></li><li>}</li></ol></pre> <p id="ZH-CN_TOPIC_0000002084257249__p1567420215144659">上例中定义了一个名为 add 的函数,其参数列表由两个 Int64 类型的参数 a 和 b 组成,函数返回值类型为 Int64,函数体中将 a 和 b 相加并返回。</p> <p id="ZH-CN_TOPIC_0000002084257249__p1511263104144659">详细介绍可参考<a href="https://developer.huawei.com/consumer/cn/doc/cangjie-guides-V5/define_functions-V5">函数</a>模块介绍。</p> </div> <div></div></div> <br /><br /><br /><br /> ## 基础数据类型 整数类型 浮点类型 布尔类型 字符类型 字符串类型 元组类型 数组类型 区间类型 Unit 类型 Nothing 类型 ### 整数类型 <div _ngcontent-apy-c173="" class="markdown-body ng-star-inserted" style="position: relative;"> <div id="body1497412078144659"><p id="ZH-CN_TOPIC_0000002084338677__p712358934144659">整数类型分为有符号(signed)整数类型和无符号(unsigned)整数类型。</p> <p id="ZH-CN_TOPIC_0000002084338677__p1653329031144659"><strong>有符号整数类型</strong>包括 Int8、Int16、Int32、Int64 和 IntNative,分别用于表示编码长度为 8-bit、16-bit、32-bit、64-bit 和平台相关大小的有符号整数值的类型。</p> <p id="ZH-CN_TOPIC_0000002084338677__p94176077144659"><strong>无符号整数类型</strong>包括 UInt8、UInt16、UInt32、UInt64 和 UIntNative,分别用于表示编码长度为 8-bit、16-bit、32-bit、64-bit 和平台相关大小的无符号整数值的类型。</p> <p id="ZH-CN_TOPIC_0000002084338677__p847207033144659">对于编码长度为 N 的有符号整数类型,其表示范围为:<span><img originheight="38" originwidth="127" src="https://alliance-communityfile-drcn.dbankcdn.com/FileServer/getFile/cmtyPub/011/111/111/0000000000011111111.20241025170611.50601711653609359449127959419477:50001231000000:2800:B409B72EF5E22C81F5207E93B13AB67B79487E9A34E712D90B0A6A74C93443DD.png?needInitFileName=true?needInitFileName=true" class="notEnlarge" width="127" height="38"></span>;对于编码长度为 N 的无符号整数类型,其表示范围为:<span><img originheight="38" originwidth="87" src="https://alliance-communityfile-drcn.dbankcdn.com/FileServer/getFile/cmtyPub/011/111/111/0000000000011111111.20241025170611.57069168947159217123836183799559:50001231000000:2800:A1395777BA3E70BF70FED1FE0B2720E3251D0775EC16E254E0C3A3AC5F003684.png?needInitFileName=true?needInitFileName=true" class="notEnlarge" width="87" height="38"></span>。下表列出了所有整数类型的表示范围:</p> <div class="tablenoborder"><div class="tbBox"><table id="table1532252474144659" class="layoutFixed idpTab"><thead><tr id="ZH-CN_TOPIC_0000002084338677__row88974934144659"><th align="left" class="cellrowborder" id="mcps1.3.5.1.3.1.1" valign="top" width="50%"><p id="ZH-CN_TOPIC_0000002084338677__entry908555147144659p0">类型</p> </th> <th align="left" class="cellrowborder" id="mcps1.3.5.1.3.1.2" valign="top" width="50%"><p id="ZH-CN_TOPIC_0000002084338677__entry1838895317144659p0">表示范围</p> </th> </tr> </thead> <tbody><tr id="ZH-CN_TOPIC_0000002084338677__row1221652950144659"><td class="cellrowborder" valign="top" width="50%"><p id="ZH-CN_TOPIC_0000002084338677__entry2138709473144659p0">Int8</p> </td> <td class="cellrowborder" valign="top" width="50%"><p id="ZH-CN_TOPIC_0000002084338677__entry1182089185144659p0"><span><img originheight="38" originwidth="219" src="https://alliance-communityfile-drcn.dbankcdn.com/FileServer/getFile/cmtyPub/011/111/111/0000000000011111111.20241025170611.01545054540783883013293651310143:50001231000000:2800:BCABFF50181F016579C7BD852FA6AC1AEB067E3067F1E1E4144FCEBAC7D20EEE.png?needInitFileName=true?needInitFileName=true" class="notEnlarge" width="219" height="38"></span></p> </td> </tr> <tr id="ZH-CN_TOPIC_0000002084338677__row643742064144659"><td class="cellrowborder" valign="top" width="50%"><p id="ZH-CN_TOPIC_0000002084338677__entry548539484144659p0">Int16</p> </td> <td class="cellrowborder" valign="top" width="50%"><p id="ZH-CN_TOPIC_0000002084338677__entry1742660918144659p0"><span><img originheight="38" originwidth="292" src="https://alliance-communityfile-drcn.dbankcdn.com/FileServer/getFile/cmtyPub/011/111/111/0000000000011111111.20241025170612.09707083203134531852314212764138:50001231000000:2800:A885E90078C3664FBD1D6A37EB6756C0BB796DA8DB583E619FFA3BAC7332544D.png?needInitFileName=true?needInitFileName=true" class="notEnlarge" width="247" height="32.14383561643836"></span></p> </td> </tr> <tr id="ZH-CN_TOPIC_0000002084338677__row75005879144659"><td class="cellrowborder" valign="top" width="50%"><p id="ZH-CN_TOPIC_0000002084338677__entry1987133937144659p0">Int32</p> </td> <td class="cellrowborder" valign="top" width="50%"><p id="ZH-CN_TOPIC_0000002084338677__entry282370175144659p0"><span><img originheight="38" originwidth="440" src="https://alliance-communityfile-drcn.dbankcdn.com/FileServer/getFile/cmtyPub/011/111/111/0000000000011111111.20241025170612.41595100718579734646598136568291:50001231000000:2800:5B459CBD9927D00F853EB0985D9EC8E6E5F3F09C88B54A7A3086FCC799D0FBA8.png?needInitFileName=true?needInitFileName=true" width="247" height="21.331818181818182"></span></p> </td> </tr> <tr id="ZH-CN_TOPIC_0000002084338677__row722755023144659"><td class="cellrowborder" valign="top" width="50%"><p id="ZH-CN_TOPIC_0000002084338677__entry2050599404144659p0">Int64</p> </td> <td class="cellrowborder" valign="top" width="50%"><p id="ZH-CN_TOPIC_0000002084338677__entry791539258144659p0"><span><img originheight="38" originwidth="697" src="https://alliance-communityfile-drcn.dbankcdn.com/FileServer/getFile/cmtyPub/011/111/111/0000000000011111111.20241025170612.04681054674587436832478534847526:50001231000000:2800:E8A8877EE1097A5D9C8B2A913666ECFBF30A216FCF1B121B59BED364EB76AFCD.png?needInitFileName=true?needInitFileName=true" width="247" height="13.466284074605452"></span></p> </td> </tr> <tr id="ZH-CN_TOPIC_0000002084338677__row287281099144659"><td class="cellrowborder" valign="top" width="50%"><p id="ZH-CN_TOPIC_0000002084338677__entry119423789144659p0">IntNative</p> </td> <td class="cellrowborder" valign="top" width="50%"><p id="ZH-CN_TOPIC_0000002084338677__entry279628419144659p0">platform dependent</p> </td> </tr> <tr id="ZH-CN_TOPIC_0000002084338677__row139746616144659"><td class="cellrowborder" valign="top" width="50%"><p id="ZH-CN_TOPIC_0000002084338677__entry1577984393144659p0">UInt8</p> </td> <td class="cellrowborder" valign="top" width="50%"><p id="ZH-CN_TOPIC_0000002084338677__entry1445657003144659p0"><span><img originheight="38" originwidth="168" src="https://alliance-communityfile-drcn.dbankcdn.com/FileServer/getFile/cmtyPub/011/111/111/0000000000011111111.20241025170612.75377966614601576194583738705005:50001231000000:2800:12EAE6793829A031F576896325E3198D41825E5D3102BBC43D31613AFF723D7D.png?needInitFileName=true?needInitFileName=true" class="notEnlarge" width="168" height="38"></span></p> </td> </tr> <tr id="ZH-CN_TOPIC_0000002084338677__row1393600428144659"><td class="cellrowborder" valign="top" width="50%"><p id="ZH-CN_TOPIC_0000002084338677__entry2067690777144659p0">UInt16</p> </td> <td class="cellrowborder" valign="top" width="50%"><p id="ZH-CN_TOPIC_0000002084338677__entry1751718767144659p0"><span><img originheight="38" originwidth="204" src="https://alliance-communityfile-drcn.dbankcdn.com/FileServer/getFile/cmtyPub/011/111/111/0000000000011111111.20241025170612.48199924671187279840606535678294:50001231000000:2800:38D116D858D3E0A101B2C0A16A24E49BCE4C39F67E1254596FD0EF52CE2CC6C9.png?needInitFileName=true?needInitFileName=true" class="notEnlarge" width="204" height="38"></span></p> </td> </tr> <tr id="ZH-CN_TOPIC_0000002084338677__row915198063144659"><td class="cellrowborder" valign="top" width="50%"><p id="ZH-CN_TOPIC_0000002084338677__entry218952006144659p0">UInt32</p> </td> <td class="cellrowborder" valign="top" width="50%"><p id="ZH-CN_TOPIC_0000002084338677__entry71688933144659p0"><span><img originheight="38" originwidth="278" src="https://alliance-communityfile-drcn.dbankcdn.com/FileServer/getFile/cmtyPub/011/111/111/0000000000011111111.20241025170612.52316212820521766188827591363794:50001231000000:2800:BAE6C81BB1B4CD2622A74E02C93BD4597010CC2519F0174FC47A24269305FC06.png?needInitFileName=true?needInitFileName=true" class="notEnlarge" width="247" height="33.76258992805756"></span></p> </td> </tr> <tr id="ZH-CN_TOPIC_0000002084338677__row1056315582144659"><td class="cellrowborder" valign="top" width="50%"><p id="ZH-CN_TOPIC_0000002084338677__entry1656481762144659p0">UInt64</p> </td> <td class="cellrowborder" valign="top" width="50%"><p id="ZH-CN_TOPIC_0000002084338677__entry1332992029144659p0"><span><img originheight="38" originwidth="419" src="https://alliance-communityfile-drcn.dbankcdn.com/FileServer/getFile/cmtyPub/011/111/111/0000000000011111111.20241025170612.72167839498096253057621576021748:50001231000000:2800:9D042397056E5B8346EF926A7DA1D96878CCF8C36ED187425FEC76DE1F22C671.png?needInitFileName=true?needInitFileName=true" width="247" height="22.400954653937948"></span></p> </td> </tr> <tr id="ZH-CN_TOPIC_0000002084338677__row2088198537144659"><td class="cellrowborder" valign="top" width="50%"><p id="ZH-CN_TOPIC_0000002084338677__entry645071662144659p0">UIntNative</p> </td> <td class="cellrowborder" valign="top" width="50%"><p id="ZH-CN_TOPIC_0000002084338677__entry1186702248144659p0">platform dependent</p> </td> </tr> </tbody></table></div> </div> <p id="ZH-CN_TOPIC_0000002084338677__p1062465698144659">程序具体使用哪种整数类型,取决于该程序中需要处理的整数的性质和范围。在 Int64 类型适合的情况下,首选 Int64 类型,因为 Int64 的表示范围足够大,并且<a href="https://developer.huawei.com/consumer/cn/doc/cangjie-guides-V5/integer-V5#整数类型字面量">整数类型字面量</a>在没有类型上下文的情况下默认推断为 Int64 类型,可以避免不必要的类型转换。</p> <div class="tiledSection"><h2 id="整数类型字面量">整数类型字面量<i class="anchorIcon" anchorid="整数类型字面量" tips="复制节点链接"></i></h2><p id="ZH-CN_TOPIC_0000002084338677__p1308191529144659">整数类型字面量有 4 种进制表示形式:二进制(使用 0b 或 0B 前缀)、八进制(使用 0o 或 0O 前缀)、十进制(没有前缀)、十六进制(使用 0x 或 0X 前缀)。例如,对于十进制数 24,表示成二进制是 0b00011000(或 0B00011000),表示成八进制是 0o30(或 0O30),表示成十六进制是 0x18(或 0X18)。</p> <p id="ZH-CN_TOPIC_0000002084338677__p1218068411144659">在各进制表示中,可以使用下划线 _ 充当分隔符的作用,方便识别数值的位数,如 0b0001_1000。</p> <p id="ZH-CN_TOPIC_0000002084338677__p1136418675144659">对于整数类型字面量,如果它的值超出了上下文要求的整数类型的表示范围,编译器将会报错。</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002084338677__screen2069390899144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">let</span> <span class="hljs-variable">x</span>: <span class="hljs-keyword">Int8</span> = <span class="hljs-number">128</span> <span class="hljs-comment">// Error, 128 out of the range of Int8</span></li><li><span class="hljs-keyword">let</span> <span class="hljs-variable">y</span>: <span class="hljs-keyword">UInt8</span> = <span class="hljs-number">256</span> <span class="hljs-comment">// Error, 256 out of the range of UInt8</span></li><li><span class="hljs-keyword">let</span> <span class="hljs-variable">z</span>: <span class="hljs-keyword">Int32</span> = <span class="hljs-number">0x8000_0000</span> <span class="hljs-comment">// Error, 0x8000_0000 out of the range of Int32</span></li></ol></pre> <p id="ZH-CN_TOPIC_0000002084338677__p618828892144659">在使用整数类型字面量时,可以通过加入后缀来明确整数字面量的类型,后缀与类型的对应为:</p> <div class="tablenoborder"><div class="tbBox"><table id="table838621422144659" class="layoutFixed idpTab"><thead><tr id="ZH-CN_TOPIC_0000002084338677__row488100204144659"><th align="left" class="cellrowborder" id="mcps1.3.7.7.1.5.1.1" valign="top" width="25%"><p id="ZH-CN_TOPIC_0000002084338677__entry1591273245144659p0">后缀</p> </th> <th align="left" class="cellrowborder" id="mcps1.3.7.7.1.5.1.2" valign="top" width="25%"><p id="ZH-CN_TOPIC_0000002084338677__entry1950653073144659p0">类型</p> </th> <th align="left" class="cellrowborder" id="mcps1.3.7.7.1.5.1.3" valign="top" width="25%"><p id="ZH-CN_TOPIC_0000002084338677__entry1308773433144659p0">后缀</p> </th> <th align="left" class="cellrowborder" id="mcps1.3.7.7.1.5.1.4" valign="top" width="25%"><p id="ZH-CN_TOPIC_0000002084338677__entry1836775743144659p0">类型</p> </th> </tr> </thead> <tbody><tr id="ZH-CN_TOPIC_0000002084338677__row1431194328144659"><td class="cellrowborder" valign="top" width="25%"><p id="ZH-CN_TOPIC_0000002084338677__entry1866981967144659p0">i8</p> </td> <td class="cellrowborder" valign="top" width="25%"><p id="ZH-CN_TOPIC_0000002084338677__entry1283542496144659p0">Int8</p> </td> <td class="cellrowborder" valign="top" width="25%"><p id="ZH-CN_TOPIC_0000002084338677__entry993723536144659p0">u8</p> </td> <td class="cellrowborder" valign="top" width="25%"><p id="ZH-CN_TOPIC_0000002084338677__entry833931775144659p0">UInt8</p> </td> </tr> <tr id="ZH-CN_TOPIC_0000002084338677__row1339725997144659"><td class="cellrowborder" valign="top" width="25%"><p id="ZH-CN_TOPIC_0000002084338677__entry1542935707144659p0">i16</p> </td> <td class="cellrowborder" valign="top" width="25%"><p id="ZH-CN_TOPIC_0000002084338677__entry1343251835144659p0">Int16</p> </td> <td class="cellrowborder" valign="top" width="25%"><p id="ZH-CN_TOPIC_0000002084338677__entry715544145144659p0">u16</p> </td> <td class="cellrowborder" valign="top" width="25%"><p id="ZH-CN_TOPIC_0000002084338677__entry1768734069144659p0">UInt16</p> </td> </tr> <tr id="ZH-CN_TOPIC_0000002084338677__row505077633144659"><td class="cellrowborder" valign="top" width="25%"><p id="ZH-CN_TOPIC_0000002084338677__entry90344325144659p0">i32</p> </td> <td class="cellrowborder" valign="top" width="25%"><p id="ZH-CN_TOPIC_0000002084338677__entry1072153933144659p0">Int32</p> </td> <td class="cellrowborder" valign="top" width="25%"><p id="ZH-CN_TOPIC_0000002084338677__entry1726373928144659p0">u32</p> </td> <td class="cellrowborder" valign="top" width="25%"><p id="ZH-CN_TOPIC_0000002084338677__entry650668780144659p0">UInt32</p> </td> </tr> <tr id="ZH-CN_TOPIC_0000002084338677__row1268004805144659"><td class="cellrowborder" valign="top" width="25%"><p id="ZH-CN_TOPIC_0000002084338677__entry1281368997144659p0">i64</p> </td> <td class="cellrowborder" valign="top" width="25%"><p id="ZH-CN_TOPIC_0000002084338677__entry9285470144659p0">Int64</p> </td> <td class="cellrowborder" valign="top" width="25%"><p id="ZH-CN_TOPIC_0000002084338677__entry662565234144659p0">u64</p> </td> <td class="cellrowborder" valign="top" width="25%"><p id="ZH-CN_TOPIC_0000002084338677__entry922711528144659p0">UInt64</p> </td> </tr> </tbody></table></div> </div> <p id="ZH-CN_TOPIC_0000002084338677__p2027870607144659">加入了后缀的整数字面量可以像下面的方式来使用:</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002084338677__screen1088920861144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">var</span> <span class="hljs-variable">x</span> = <span class="hljs-number">100i8</span> <span class="hljs-comment">// x is 100 with type Int8</span></li><li><span class="hljs-keyword">var</span> <span class="hljs-variable">y</span> = <span class="hljs-number">0x10u64</span> <span class="hljs-comment">// y is 16 with type UInt64</span></li><li><span class="hljs-keyword">var</span> <span class="hljs-variable">z</span> = <span class="hljs-number">0o432i32</span> <span class="hljs-comment">// z is 282 with type Int32</span></li></ol></pre> </div> <div class="tiledSection"><h2 id="字符字节字面量">字符字节字面量<i class="anchorIcon" anchorid="字符字节字面量" tips="复制节点链接"></i></h2><p id="ZH-CN_TOPIC_0000002084338677__p1443396280144659">仓颉编程语言支持字符字节字面量,以方便使用 ASCII 码表示 UInt8 类型的值。字符字节字面量由字符 b、一对标识首尾的单引号、以及一个 ASCII 字符组成,例如:</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002084338677__screen850717014144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">var</span> <span class="hljs-variable">a</span> = <span class="hljs-number">b'x'</span> <span class="hljs-comment">// a is 120 with type UInt8</span></li><li><span class="hljs-keyword">var</span> <span class="hljs-variable">b</span> = <span class="hljs-number">b'\n'</span> <span class="hljs-comment">// b is 10 with type UInt8</span></li><li><span class="hljs-keyword">var</span> <span class="hljs-variable">c</span> = <span class="hljs-number">b'\u{78}'</span> <span class="hljs-comment">// c is 120 with type UInt8</span></li></ol></pre> <p id="ZH-CN_TOPIC_0000002084338677__p1229775378144659">b'x' 表示类型为 UInt8 大小是 120 的字面值。另外还可以通过 b'\u{78}' 这种转义形式表示类型为 UInt8,16 进制大小为 0x78 或 10 进制大小为 120 的字面值。需要注意的是,\u 内部最多有两位 16 进制数,并且值必须小于 256(十进制)。</p> </div> <div class="tiledSection"><h2 id="整数类型支持的操作">整数类型支持的操作<i class="anchorIcon" anchorid="整数类型支持的操作" tips="复制节点链接"></i></h2><p id="ZH-CN_TOPIC_0000002084338677__p1701539286144659">整数类型默认支持的操作符包括:算术操作符、位操作符、关系操作符、自增和自减操作符、赋值操作符、复合赋值操作符。各操作符的优先级参见附录中的<a href="https://developer.huawei.com/consumer/cn/doc/cangjie-guides-V5/operator-V5">操作符</a>。</p> <ol id="ZH-CN_TOPIC_0000002084338677__ol2125692846144659"><li id="li1184990394144659"><p id="ZH-CN_TOPIC_0000002084338677__p661460267144659">算术操作符包括:一元负号(-)、加法(+)、减法(-)、乘法(*)、除法(/)、取模(%)、幂运算(**)。</p> <ul id="ZH-CN_TOPIC_0000002084338677__ul192561250144659"><li id="li885288442144659"><p id="ZH-CN_TOPIC_0000002084338677__p1364214416144659">除了一元负号(-)和幂运算(**),其他操作符要求左右操作数是相同的类型。</p> </li><li id="li102977695144659"><p id="ZH-CN_TOPIC_0000002084338677__p232037874144659">*,/,+ 和 - 的操作数可以是整数类型或浮点类型。</p> </li><li id="li1338398086144659"><p id="ZH-CN_TOPIC_0000002084338677__p531738164144659">% 的操作数只支持整数类型。</p> </li><li id="li872974423144659"><p id="ZH-CN_TOPIC_0000002084338677__p652381569144659">** 的左操作数只能为 Int64 类型或 Float64 类型,并且:</p> <ul id="ZH-CN_TOPIC_0000002084338677__ul330205811144659"><li id="li1213126940144659">当左操作数类型为 Int64 时,右操作数只能为 UInt64 类型,表达式的类型为 Int64。</li><li id="li1582858556144659">当左操作数类型为 Float64 时,右操作数只能为 Int64 类型或 Float64 类型,表达式的类型为 Float64。</li></ul> </li></ul> <p id="ZH-CN_TOPIC_0000002084338677__p347490622144659">幂运算的使用,见如下示例:</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002084338677__screen29175172144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">let</span> <span class="hljs-variable">p1</span> = <span class="hljs-number">2</span> ** <span class="hljs-number">3</span> <span class="hljs-comment">// p1 = 8</span></li><li><span class="hljs-keyword">let</span> <span class="hljs-variable">p2</span> = <span class="hljs-number">2</span> ** <span class="hljs-keyword">UInt64</span>(<span class="hljs-number">3</span> ** <span class="hljs-number">2</span>) <span class="hljs-comment">// p2 = 512</span></li><li><span class="hljs-keyword">let</span> <span class="hljs-variable">p3</span> = <span class="hljs-number">2.0</span> ** <span class="hljs-number">3.0</span> <span class="hljs-comment">// p3 = 8.0</span></li><li><span class="hljs-keyword">let</span> <span class="hljs-variable">p4</span> = <span class="hljs-number">2.0</span> ** <span class="hljs-number">3</span> ** <span class="hljs-number">2</span> <span class="hljs-comment">// p4 = 512.0</span></li><li><span class="hljs-keyword">let</span> <span class="hljs-variable">p5</span> = <span class="hljs-number">2.0</span> ** <span class="hljs-number">3.0</span> <span class="hljs-comment">// p5 = 8.0</span></li><li><span class="hljs-keyword">let</span> <span class="hljs-variable">p6</span> = <span class="hljs-number">2.0</span> ** <span class="hljs-number">3.0</span> ** <span class="hljs-number">2.0</span> <span class="hljs-comment">// p6 = 512.0</span></li></ol></pre> </li><li id="li1589816847144659"><p id="ZH-CN_TOPIC_0000002084338677__p529253326144659">位操作符包括:按位求反(!)、左移(<<)、右移(>>)、按位与(&)、按位异或(^)、按位或(|)。注意,按位与、按位异或和按位或操作符要求左右操作数是相同的整数类型。</p> </li><li id="li686965852144659"><p id="ZH-CN_TOPIC_0000002084338677__p1716666616144659">关系操作符包括:小于(<)、大于(>)、小于等于(<=)、大于等于(>=)、相等(==)、不等(!=)。要求关系操作符的左右操作数是相同的整数类型。</p> </li><li id="li1021327046144659"><p id="ZH-CN_TOPIC_0000002084338677__p199447388144659">自增和自减操作符包括:自增(++)和自减(--)。注意,仓颉中的自增和自减操作符只能作为一元后缀操作符使用。</p> </li><li id="li1607015783144659"><p id="ZH-CN_TOPIC_0000002084338677__p218832695144659">赋值操作符即 =,复合赋值操作符包括:+=、-=、*=、/=、%=、**=、<<=、>>=、&=、^=、|=。</p> </li></ol> <p id="ZH-CN_TOPIC_0000002084338677__p1406770698144659">整数类型之间、整数类型和浮点类型之间可以互相转换,整数类型可以转换为字符类型,具体的类型转换语法及规则请参见<a href="https://developer.huawei.com/consumer/cn/doc/cangjie-guides-V5/typecast-V5#数值类型之间的转换">数值类型之间的转换</a>。</p> <div><div class="hw-editor-tip warn"><div class="title">注意</div><div class="content"><p id="ZH-CN_TOPIC_0000002084338677__p682574382144659">本章中我们所提及的某个类型支持的操作,均是指在没有<a href="https://developer.huawei.com/consumer/cn/doc/cangjie-guides-V5/operator_overloading-V5">操作符重载</a>的前提下。</p> </div></div></div> </div> </div> <div></div></div> ### 浮点类型 <div _ngcontent-apy-c173="" class="markdown-body ng-star-inserted" style="position: relative;"> <div id="body399403882144659"><p id="ZH-CN_TOPIC_0000002048298036__p1363194327144659">浮点类型包括 Float16、 Float32 和 Float64,分别用于表示编码长度为 16-bit、 32-bit 和 64-bit 的浮点数(带小数部分的数字,如 3.14159、8.24 和 0.1 等)的类型。Float16、 Float32 和 Float64 分别对应 IEEE 754 中的半精度格式(即 binary16)、单精度格式(即 binary32)和双精度格式(即 binary64)。</p> <p id="ZH-CN_TOPIC_0000002048298036__p819126052144659">Float64 的精度约为小数点后 15 位,Float32 的精度约为小数点后 6 位,Float16 的精度约为小数点后 3 位。使用哪种浮点类型,取决于代码中需要处理的浮点数的性质和范围。在多种浮点类型都适合的情况下,首选精度高的浮点类型,因为精度低的浮点类型的累计计算误差很容易扩散,并且它能精确表示的整数范围也很有限。</p> <div class="tiledSection"><h2 id="浮点类型字面量">浮点类型字面量<i class="anchorIcon" anchorid="浮点类型字面量" tips="复制节点链接"></i></h2><p id="ZH-CN_TOPIC_0000002048298036__p975229051144659">浮点类型字面量有两种进制表示形式:十进制、十六进制。在十进制表示中,一个浮点字面量至少要包含一个整数部分或一个小数部分,没有小数部分时必须包含指数部分(以 e 或 E 为前缀,底数为 10)。在十六进制表示中,一个浮点字面量除了至少要包含一个整数部分或小数部分(以 0x 或 0X 为前缀),同时必须包含指数部分(以 p 或 P 为前缀,底数为 2)。</p> <p id="ZH-CN_TOPIC_0000002048298036__p1918709272144659">下面的例子展示了浮点字面量的使用:</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002048298036__screen280526412144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">let</span> <span class="hljs-variable">a</span>: <span class="hljs-keyword">Float32</span> = <span class="hljs-number">3.14</span></li><li><span class="hljs-keyword">let</span> <span class="hljs-variable">b</span>: <span class="hljs-keyword">Float32</span> = <span class="hljs-number">2e3</span></li><li><span class="hljs-keyword">let</span> <span class="hljs-variable">c</span>: <span class="hljs-keyword">Float32</span> = <span class="hljs-number">2.4e-1</span></li><li><span class="hljs-keyword">let</span> <span class="hljs-variable">d</span>: <span class="hljs-keyword">Float64</span> =<span class="hljs-number"> .123e2</span></li><li><span class="hljs-keyword">let</span> <span class="hljs-variable">e</span>: <span class="hljs-keyword">Float64</span> = <span class="hljs-number">0x1</span><span class="hljs-number">.1p0</span></li><li><span class="hljs-keyword">let</span> <span class="hljs-variable">f</span>: <span class="hljs-keyword">Float64</span> = <span class="hljs-number">0x1p2</span></li><li><span class="hljs-keyword">let</span> <span class="hljs-variable">g</span>: <span class="hljs-keyword">Float64</span> = <span class="hljs-number">0x</span><span class="hljs-number">.2p4</span></li></ol></pre> <p id="ZH-CN_TOPIC_0000002048298036__p125626615144659">在使用十进制浮点数字面量时,可以通过加入后缀来明确浮点数字面量的类型,后缀与类型的对应为:</p> <div class="tablenoborder"><div class="tbBox"><table id="table1114060150144659" class="layoutFixed idpTab"><thead><tr id="ZH-CN_TOPIC_0000002048298036__row352471544144659"><th align="left" class="cellrowborder" id="mcps1.3.3.6.1.3.1.1" valign="top" width="50%">后缀</th> <th align="left" class="cellrowborder" id="mcps1.3.3.6.1.3.1.2" valign="top" width="50%">类型</th> </tr> </thead> <tbody><tr id="ZH-CN_TOPIC_0000002048298036__row1267194364144659"><td class="cellrowborder" valign="top" width="50%">f16</td> <td class="cellrowborder" valign="top" width="50%">Float16</td> </tr> <tr id="ZH-CN_TOPIC_0000002048298036__row596970491144659"><td class="cellrowborder" valign="top" width="50%">f32</td> <td class="cellrowborder" valign="top" width="50%">Float32</td> </tr> <tr id="ZH-CN_TOPIC_0000002048298036__row1067399915144659"><td class="cellrowborder" valign="top" width="50%">f64</td> <td class="cellrowborder" valign="top" width="50%">Float64</td> </tr> </tbody></table></div> </div> <p id="ZH-CN_TOPIC_0000002048298036__p323385840144659">加入了后缀的浮点数字面量可以像下面的方式来使用:</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002048298036__screen643351261144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">let</span> <span class="hljs-variable">a</span> = <span class="hljs-number">3.14f32</span> <span class="hljs-comment">// a is 3.14 with type Float32</span></li><li><span class="hljs-keyword">let</span> <span class="hljs-variable">b</span> = <span class="hljs-number">2e3f32</span> <span class="hljs-comment">// b is 2e3 with type Float32</span></li><li><span class="hljs-keyword">let</span> <span class="hljs-variable">c</span> = <span class="hljs-number">2.4e-1f64</span> <span class="hljs-comment">// c is 2.4e-1 with type Float64</span></li><li><span class="hljs-keyword">let</span> <span class="hljs-variable">d</span> =<span class="hljs-number"> .123e2</span><span class="hljs-variable">f64</span> <span class="hljs-comment">// d is .123e2 with type Float64</span></li></ol></pre> </div> <div class="tiledSection"><h2 id="浮点类型支持的操作">浮点类型支持的操作<i class="anchorIcon" anchorid="浮点类型支持的操作" tips="复制节点链接"></i></h2><p id="ZH-CN_TOPIC_0000002048298036__p741827844144659">浮点类型默认支持的操作符包括:算术操作符、关系操作符、赋值操作符、复合赋值操作符。浮点类型不支持自增和自减操作符。</p> <p id="ZH-CN_TOPIC_0000002048298036__p519430564144659">浮点类型之间、浮点类型和整数类型之间可以互相转换,具体的类型转换语法及规则请参见<a href="https://developer.huawei.com/consumer/cn/doc/cangjie-guides-V5/typecast-V5#数值类型之间的转换">数值类型之间的转换</a>。</p> </div> </div> <div></div></div> ### 布尔类型 <div _ngcontent-apy-c173="" class="markdown-body ng-star-inserted" style="position: relative;"> <div id="body1153905806144659"><p id="ZH-CN_TOPIC_0000002084257253__p1973189752144659">布尔类型使用 Bool 表示,用来表示逻辑中的真和假。</p> <div class="tiledSection"><h2 id="布尔类型字面量">布尔类型字面量<i class="anchorIcon" anchorid="布尔类型字面量" tips="复制节点链接"></i></h2><p id="ZH-CN_TOPIC_0000002084257253__p484922453144659">布尔类型只有两个字面量:true 和 false。</p> <p id="ZH-CN_TOPIC_0000002084257253__p1141745118144659">下面的例子展示了布尔字面量的使用:</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002084257253__screen328992044144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">let</span> <span class="hljs-variable">a</span>: <span class="hljs-keyword">Bool</span> = <span class="hljs-keyword">true</span></li><li><span class="hljs-keyword">let</span> <span class="hljs-variable">b</span>: <span class="hljs-keyword">Bool</span> = <span class="hljs-keyword">false</span></li></ol></pre> </div> <div class="tiledSection"><h2 id="布尔类型支持的操作">布尔类型支持的操作<i class="anchorIcon" anchorid="布尔类型支持的操作" tips="复制节点链接"></i></h2><p id="ZH-CN_TOPIC_0000002084257253__p632497475144659">布尔类型支持的操作符包括:逻辑操作符(逻辑非 !,逻辑与 &&,逻辑或 ||)、部分关系操作符(== 和 !=)、赋值操作符、部分复合赋值操作符(&&= 和 ||=)。</p> </div> </div> <div></div></div> ### 字符类型 <div _ngcontent-apy-c173="" class="markdown-body ng-star-inserted" style="position: relative;"> <div id="body1300062933144659"><p id="ZH-CN_TOPIC_0000002048139776__p764785260144659">字符类型使用 Rune 表示,可以表示 Unicode 字符集中的所有字符。</p> <div class="tiledSection"><h2 id="字符类型字面量">字符类型字面量<i class="anchorIcon" anchorid="字符类型字面量" tips="复制节点链接"></i></h2><p id="ZH-CN_TOPIC_0000002048139776__p2060763244144659">字符类型字面量有三种形式:单个字符、转义字符和通用字符。一个 Rune 字面量由字符 r 开头,后跟一个由一对单引号或双引号包含的字符。</p> <p id="ZH-CN_TOPIC_0000002048139776__p1289525450144659">单个字符的字符字面量举例:</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002048139776__screen2024706825144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">let</span> <span class="hljs-variable">a</span>: <span class="hljs-keyword">Rune</span> = <span class="hljs-variable">r</span><span class="hljs-string">'a'</span></li><li><span class="hljs-keyword">let</span> <span class="hljs-variable">b</span>: <span class="hljs-keyword">Rune</span> = <span class="hljs-variable">r</span><span class="hljs-string">"b"</span></li></ol></pre> <p id="ZH-CN_TOPIC_0000002048139776__p1369091136144659">转义字符是指在一个字符序列中对后面的字符进行另一种解释的字符。转义字符使用转义符号 \ 开头,后面加需要转义的字符。举例如下:</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002048139776__screen240168884144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">let</span> <span class="hljs-variable">slash</span>: <span class="hljs-keyword">Rune</span> = <span class="hljs-variable">r</span><span class="hljs-string">'\\'</span></li><li><span class="hljs-keyword">let</span> <span class="hljs-variable">newLine</span>: <span class="hljs-keyword">Rune</span> = <span class="hljs-variable">r</span><span class="hljs-string">'\n'</span></li><li><span class="hljs-keyword">let</span> <span class="hljs-variable">tab</span>: <span class="hljs-keyword">Rune</span> = <span class="hljs-variable">r</span><span class="hljs-string">'\t'</span></li></ol></pre> <p id="ZH-CN_TOPIC_0000002048139776__p867603065144659">通用字符以 \u 开头,后面加上定义在一对花括号中的 1~8 个十六进制数,即可表示对应的 Unicode 值代表的字符。举例如下:</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002048139776__screen1432901674144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">main</span>() {</li><li> <span class="hljs-keyword">let</span> <span class="hljs-variable">he</span>: <span class="hljs-keyword">Rune</span> = <span class="hljs-variable">r</span><span class="hljs-string">'\u{4f60}'</span></li><li> <span class="hljs-keyword">let</span> <span class="hljs-variable">llo</span>: <span class="hljs-keyword">Rune</span> = <span class="hljs-variable">r</span><span class="hljs-string">'\u{597d}'</span></li><li> <span class="hljs-title function_">print</span>(<span class="hljs-variable">he</span>)</li><li> <span class="hljs-title function_">print</span>(<span class="hljs-variable">llo</span>)</li><li>}</li></ol></pre> <p id="ZH-CN_TOPIC_0000002048139776__p1587963155144659">编译并执行上述代码,输出结果为:</p> <pre class="text prettyprint linenums hljs language-plaintext" id="ZH-CN_TOPIC_0000002048139776__screen2139696483144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li>你好</li></ol></pre> </div> <div class="tiledSection"><h2 id="字符类型支持的操作">字符类型支持的操作<i class="anchorIcon" anchorid="字符类型支持的操作" tips="复制节点链接"></i></h2><p id="ZH-CN_TOPIC_0000002048139776__p216603350144659">字符类型仅支持关系操作符:小于(<)、大于(>)、小于等于(<=)、大于等于(>=)、相等(==)、不等(!=)。比较的是字符的 Unicode 值。</p> <p id="ZH-CN_TOPIC_0000002048139776__p1769786917144659">Rune 可以转换为 UInt32,整数类型可以转换为 Rune,具体的类型转换语法及规则请参见<a href="https://developer.huawei.com/consumer/cn/doc/cangjie-guides-V5/typecast-V5#rune-到-uint32-和整数类型到-rune-的转换">Rune 到 UInt32 和整数类型到 Rune 的转换</a>。</p> </div> </div> <div></div></div> ### 字符串类型 <div _ngcontent-apy-c173="" class="markdown-body ng-star-inserted" style="position: relative;"> <div id="body1256515058144659"><p id="ZH-CN_TOPIC_0000002084338681__p267238697144659">字符串类型使用 String 表示,用于表达文本数据,由一串 Unicode 字符组合而成。</p> <div class="tiledSection"><h2 id="字符串字面量">字符串字面量<i class="anchorIcon" anchorid="字符串字面量" tips="复制节点链接"></i></h2><p id="ZH-CN_TOPIC_0000002084338681__p796090119144659">字符串字面量分为三类:单行字符串字面量,多行字符串字面量,多行原始字符串字面量。</p> <p id="ZH-CN_TOPIC_0000002084338681__p2058215449144659"><strong>单行字符串字面量</strong>的内容定义在一对单引号或一对双引号之内,引号中的内容可以是任意数量的(除了非转义的双引号和单独出现的 \ 之外的)任意字符。单行字符串字面量只能写在同一行,不能跨越多行。举例如下:</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002084338681__screen547048916144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">let</span> <span class="hljs-variable">s1</span>: <span class="hljs-title class_">String</span> = <span class="hljs-string">""</span></li><li><span class="hljs-keyword">let</span> <span class="hljs-variable">s2</span> = <span class="hljs-string">'Hello Cangjie Lang'</span></li><li><span class="hljs-keyword">let</span> <span class="hljs-variable">s3</span> = <span class="hljs-string">"\"Hello Cangjie Lang\""</span></li><li><span class="hljs-keyword">let</span> <span class="hljs-variable">s4</span> = <span class="hljs-string">'Hello Cangjie Lang\n'</span></li></ol></pre> <p id="ZH-CN_TOPIC_0000002084338681__p685244235144659"><strong>多行字符串字面量</strong>开头结尾需各存在三个双引号(""")或三个单引号(''')。字面量的内容从开头的三个引号换行后的第一行开始,到遇到的第一个非转义的三个引号为止,之间的内容可以是任意数量的(除单独出现的 \ 之外的)任意字符。不同于单行字符串字面量,多行字符串字面量可以跨越多行。举例如下:</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002084338681__screen1968642900144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">let</span> <span class="hljs-variable">s1</span>: <span class="hljs-title class_">String</span> = <span class="hljs-string">""</span><span class="hljs-string">"</span></li><li><span class="hljs-string"> "</span><span class="hljs-string">""</span></li><li><span class="hljs-keyword">let</span> <span class="hljs-variable">s2</span> = <span class="hljs-string">''</span><span class="hljs-string">'</span></li><li><span class="hljs-string"> Hello,</span></li><li><span class="hljs-string"> Cangjie Lang'</span><span class="hljs-string">''</span></li></ol></pre> <p id="ZH-CN_TOPIC_0000002084338681__p1006608541144659"><strong>多行原始字符串字面量</strong>以一个或多个井号(#)和一个单引号(')或双引号(")开头,后跟任意数量的合法字符,直到出现与字符串开头相同的引号和与字符串开头相同数量的井号为止。在当前文件结束之前,如果还没遇到匹配的双引号和相同个数的井号,则编译报错。与多行字符串字面量一样,原始多行字符串字面量可以跨越多行。不同之处在于,转义规则不适用于多行原始字符串字面量,字面量中的内容会维持原样(转义字符不会被转义,如下例中 s2 中的 \n 不是换行符,而是由 \ 和 n 组成的字符串 \n)。举例如下:</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002084338681__screen932426132144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">let</span> <span class="hljs-variable">s1</span>: <span class="hljs-title class_">String</span> = <span class="hljs-string">#""#</span></li><li><span class="hljs-keyword">let</span> <span class="hljs-variable">s2</span> = ##<span class="hljs-string">'\n'</span>##</li><li><span class="hljs-keyword">let</span> <span class="hljs-variable">s3</span> = <span class="hljs-string">###"</span></li><li><span class="hljs-string"> Hello,</span></li><li><span class="hljs-string"> Cangjie</span></li><li><span class="hljs-string"> Lang"###</span></li></ol></pre> <p id="ZH-CN_TOPIC_0000002084338681__p419869779144659">对于形如 left = right 的赋值操作,如果左操作数的类型是 Byte(内置类型 UInt8 的别名),并且右操作数是一个表示 ASCII 字符的字符串字面量,那么右操作数的字符串将分别被强制转换为 Byte 类型,再进行赋值;如果左操作数的类型是 Rune,并且右操作数是一个单字符的字符串字面量,那么右操作数的字符串将分别被强制转换为 Rune 类型,再进行赋值。</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002084338681__screen1342539887144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">main</span>() {</li><li> <span class="hljs-keyword">var</span> <span class="hljs-variable">b</span>: <span class="hljs-title class_">Byte</span> = <span class="hljs-string">"0"</span></li><li> <span class="hljs-title function_">print</span>(<span class="hljs-variable">b</span>)</li><li> <span class="hljs-variable">b</span> = <span class="hljs-string">"1"</span></li><li> <span class="hljs-title function_">print</span>(<span class="hljs-variable">b</span>)</li><li> <span class="hljs-keyword">var</span> <span class="hljs-variable">r</span>: <span class="hljs-keyword">Rune</span> = <span class="hljs-string">"0"</span></li><li> <span class="hljs-title function_">print</span>(<span class="hljs-variable">r</span>)</li><li> <span class="hljs-variable">r</span> = <span class="hljs-string">"1"</span></li><li> <span class="hljs-title function_">print</span>(<span class="hljs-variable">r</span>)</li><li>}</li></ol></pre> <p id="ZH-CN_TOPIC_0000002084338681__p284416278144659">编译并执行上述代码,输出结果为:</p> <pre class="text prettyprint linenums hljs language-plaintext" id="ZH-CN_TOPIC_0000002084338681__screen1159552778144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li>484901</li></ol></pre> </div> <div class="tiledSection"><h2 id="插值字符串">插值字符串<i class="anchorIcon" anchorid="插值字符串" tips="复制节点链接"></i></h2><p id="ZH-CN_TOPIC_0000002084338681__p1977594928144659">插值字符串是一种包含一个或多个插值表达式的字符串字面量(不适用于多行原始字符串字面量),通过将表达式插入到字符串中,可以有效避免字符串拼接的问题。虽然我们直到现在才介绍它,但其实它早已经出现在之前的示例代码中,因为我们经常在 println 函数中输出非字符串类型的变量值,例如 println("${x}")。</p> <p id="ZH-CN_TOPIC_0000002084338681__p230889261144659">插值表达式必须用花括号 {} 包起来,并在 {} 之前加上 $ 前缀。{} 中可以包含一个或者多个声明或表达式。</p> <p id="ZH-CN_TOPIC_0000002084338681__p1056380452144659">当插值字符串求值时,每个插值表达式所在位置会被 {} 中的最后一项的值替换,整个插值字符串最终仍是一个字符串。</p> <p id="ZH-CN_TOPIC_0000002084338681__p1016707892144659">下面是插值字符串的简单示例:</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002084338681__screen104022145144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">main</span>() {</li><li> <span class="hljs-keyword">let</span> <span class="hljs-variable">fruit</span> = <span class="hljs-string">"apples"</span></li><li> <span class="hljs-keyword">let</span> <span class="hljs-variable">count</span> = <span class="hljs-number">10</span></li><li> <span class="hljs-keyword">let</span> <span class="hljs-variable">s</span> = <span class="hljs-string">"There are <span class="hljs-subst">${<span class="hljs-variable">count</span> * <span class="hljs-variable">count</span>}</span> <span class="hljs-subst">${<span class="hljs-variable">fruit</span>}</span>"</span></li><li> <span class="hljs-title function_">println</span>(<span class="hljs-variable">s</span>)</li><li> </li><li> <span class="hljs-keyword">let</span> <span class="hljs-variable">r</span> = <span class="hljs-number">2.4</span></li><li> <span class="hljs-keyword">let</span> <span class="hljs-variable">area</span> = <span class="hljs-string">"The area of a circle with radius <span class="hljs-subst">${<span class="hljs-variable">r</span>}</span> is <span class="hljs-subst">${<span class="hljs-keyword">let</span> <span class="hljs-variable">PI</span> = <span class="hljs-number">3.141592</span>; <span class="hljs-variable">PI</span> * <span class="hljs-variable">r</span> * <span class="hljs-variable">r</span>}</span>"</span></li><li> <span class="hljs-title function_">println</span>(<span class="hljs-variable">area</span>)</li><li>}</li></ol></pre> <p id="ZH-CN_TOPIC_0000002084338681__p1138891198144659">编译并执行上述代码,输出结果为:</p> <pre class="text prettyprint linenums hljs language-plaintext" id="ZH-CN_TOPIC_0000002084338681__screen110961441144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li>There are 100 apples</li><li>The area of a circle with radius 2.400000 is 18.095570</li></ol></pre> </div> <div class="tiledSection"><h2 id="字符串类型支持的操作">字符串类型支持的操作<i class="anchorIcon" anchorid="字符串类型支持的操作" tips="复制节点链接"></i></h2><p id="ZH-CN_TOPIC_0000002084338681__p1845883719144659">字符串类型支持使用关系操作符进行比较,支持使用 + 进行拼接。下面的例子展示了字符串类型的判等和拼接:</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002084338681__screen1748288507144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">main</span>() {</li><li> <span class="hljs-keyword">let</span> <span class="hljs-variable">s1</span> = <span class="hljs-string">"abc"</span></li><li> <span class="hljs-keyword">var</span> <span class="hljs-variable">s2</span> = <span class="hljs-string">"ABC"</span></li><li> <span class="hljs-keyword">let</span> <span class="hljs-variable">r1</span> = <span class="hljs-variable">s1</span> == <span class="hljs-variable">s2</span></li><li> <span class="hljs-title function_">println</span>(<span class="hljs-string">"The result of 'abc' == 'ABC' is: <span class="hljs-subst">${<span class="hljs-variable">r1</span>}</span>"</span>)</li><li> <span class="hljs-keyword">let</span> <span class="hljs-variable">r2</span> = <span class="hljs-variable">s1</span> + <span class="hljs-variable">s2</span></li><li> <span class="hljs-title function_">println</span>(<span class="hljs-string">"The result of 'abc' + 'ABC' is: <span class="hljs-subst">${<span class="hljs-variable">r2</span>}</span>"</span>)</li><li>}</li></ol></pre> <p id="ZH-CN_TOPIC_0000002084338681__p30086159144659">编译并执行上述代码,输出结果为:</p> <pre class="text prettyprint linenums hljs language-plaintext" id="ZH-CN_TOPIC_0000002084338681__screen494654128144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li>The result of 'abc' == 'ABC' is: false</li><li>The result of 'abc' + 'ABC' is: abcABC</li></ol></pre> <p id="ZH-CN_TOPIC_0000002084338681__p676508979144659">字符串还支持其他常见操作,例如拆分、替换等。</p> </div> </div> <div></div></div> ### 元组类型 <div _ngcontent-apy-c173="" class="markdown-body ng-star-inserted" style="position: relative;"> <div id="body1190167260144659"><p id="ZH-CN_TOPIC_0000002048298040__p682389473144659">元组(Tuple)可以将多个不同的类型组合在一起,成为一个新的类型。元组类型使用 (T1, T2, ..., TN) 表示,其中 T1 到 TN 可以是任意类型,不同类型间使用逗号(,)连接。元组至少是二元,例如,(Int64, Float64) 表示一个二元组类型,(Int64, Float64, String) 表示一个三元组类型。</p> <p id="ZH-CN_TOPIC_0000002048298040__p1898339817144659">元组的长度是固定的,即一旦定义了一个元组类型的实例,它的长度不能再被更改。</p> <p id="ZH-CN_TOPIC_0000002048298040__p2023388565144659">元组类型是不可变类型,即一旦定义了一个元组类型的实例,它的内容不能再被更新。例如</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002048298040__screen1456338982144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">var</span> <span class="hljs-variable">tuple</span> = (<span class="hljs-keyword">true</span>, <span class="hljs-keyword">false</span>)</li><li><span class="hljs-variable">tuple</span>[<span class="hljs-number">0</span>] = <span class="hljs-keyword">false</span> <span class="hljs-comment">// Error, 'tuple element' can not be assigned</span></li></ol></pre> <div class="tiledSection"><h2 id="元组类型的字面量">元组类型的字面量<i class="anchorIcon" anchorid="元组类型的字面量" tips="复制节点链接"></i></h2><p id="ZH-CN_TOPIC_0000002048298040__p1618091447144659">元组类型的字面量使用 (e1, e2, ..., eN) 表示,其中 e1 到 eN 是表达式,多个表达式之间使用逗号分隔。下面的例子中,分别定义了一个 (Int64, Float64) 类型的变量 x,以及一个 (Int64, Float64, String) 类型的变量 y,并且使用元组类型的字面量为它们定义了初值:</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002048298040__screen356857735144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">let</span> <span class="hljs-variable">x</span>: (<span class="hljs-keyword">Int64</span>, <span class="hljs-keyword">Float64</span>) = (<span class="hljs-number">3</span>, <span class="hljs-number">3.141592</span>)</li><li><span class="hljs-keyword">let</span> <span class="hljs-variable">y</span>: (<span class="hljs-keyword">Int64</span>, <span class="hljs-keyword">Float64</span>, <span class="hljs-title class_">String</span>) = (<span class="hljs-number">3</span>, <span class="hljs-number">3.141592</span>, <span class="hljs-string">"PI"</span>)</li></ol></pre> <p id="ZH-CN_TOPIC_0000002048298040__p421271086144659">元组支持通过 t[index] 的方式访问某个具体位置的元素,其中 t 是一个元组,index 是下标,并且 index 只能是从 0 开始且小于元组元素个数的整数类型字面量,否则,编译报错。下面的例子中,使用 pi[0] 和 pi[1] 可以分别访问二元组 pi 的第一个元素和第二个元素。</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002048298040__screen944271037144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">main</span>() {</li><li> <span class="hljs-keyword">var</span> <span class="hljs-variable">pi</span> = (<span class="hljs-number">3.14</span>, <span class="hljs-string">"PI"</span>)</li><li> <span class="hljs-title function_">println</span>(<span class="hljs-variable">pi</span>[<span class="hljs-number">0</span>])</li><li> <span class="hljs-title function_">println</span>(<span class="hljs-variable">pi</span>[<span class="hljs-number">1</span>])</li><li>}</li></ol></pre> <p id="ZH-CN_TOPIC_0000002048298040__p856938757144659">编译并执行上述代码,输出结果为:</p> <pre class="text prettyprint linenums hljs language-plaintext" id="ZH-CN_TOPIC_0000002048298040__screen699695426144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li>3.140000</li><li>PI</li></ol></pre> <p id="ZH-CN_TOPIC_0000002048298040__p1119163637144659">在赋值表达式中,可使用元组字面量对表达式的右值进行解构,这要求赋值表达式等号左边必须是一个元组字面量,这个元组字面量里面的元素必须都是左值(左值即出现在赋值操作符左边的,可保存值的表达式,具体参见各章节对赋值操作的描述)或者一个元组字面量,当元组字面量中出现 _ 时,表示忽略等号右侧 tuple 对应位置处的求值结果(意味着这个位置处的类型检查总是可以通过的),等号右边的表达式也必须是 tuple 类型,右边 tuple 每个元素的类型必须是对应位置左值类型的子类型。注意,复合赋值不支持这种解构方式。求值顺序上先计算等号右边表达式的值,再对左值部分从左往右逐个赋值,例如:</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002048298040__screen1587655342144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">var</span> <span class="hljs-variable">a</span>: <span class="hljs-keyword">Int64</span></li><li><span class="hljs-keyword">var</span> <span class="hljs-variable">b</span>: <span class="hljs-title class_">String</span></li><li><span class="hljs-keyword">var</span> <span class="hljs-variable">c</span>: <span class="hljs-keyword">Unit</span></li><li><span class="hljs-keyword">func</span> <span class="hljs-title function_">f</span>() { ((<span class="hljs-number">1</span>, <span class="hljs-string">"abc"</span>), ()) }</li><li>((<span class="hljs-variable">a</span>, <span class="hljs-variable">b</span>), <span class="hljs-variable">c</span>) = <span class="hljs-title function_">f</span>() <span class="hljs-comment">// value of a is 1, value of b is "abc", value of c is '()'</span></li><li>((<span class="hljs-variable">a</span>, <span class="hljs-variable">b</span>), <span class="hljs-variable">_</span>) = ((<span class="hljs-number">2</span>, <span class="hljs-string">"def"</span>), <span class="hljs-number">3.0</span>) <span class="hljs-comment">// value of a is 2, value of b is "def", 3.0 is ignored</span></li></ol></pre> </div> <div class="tiledSection"><h2 id="元组类型的类型参数">元组类型的类型参数<i class="anchorIcon" anchorid="元组类型的类型参数" tips="复制节点链接"></i></h2><p id="ZH-CN_TOPIC_0000002048298040__p1662256661144659">可以为元组类型标记显式的类型参数名,下面例子中的 name 和 price 就是 类型参数名。</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002048298040__screen1586250549144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">func</span> <span class="hljs-title function_">getFruitPrice</span> (): (<span class="hljs-variable">name</span>: <span class="hljs-title class_">String</span>, <span class="hljs-variable">price</span>: <span class="hljs-keyword">Int64</span>) {</li><li> <span class="hljs-keyword">return</span> (<span class="hljs-string">"banana"</span>, <span class="hljs-number">10</span>)</li><li>}</li></ol></pre> <p id="ZH-CN_TOPIC_0000002048298040__p1878816015144659">对于一个元组类型,只允许统一写类型参数名,或者统一不写类型参数名,不允许交替存在。</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002048298040__screen279315450144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">let</span> <span class="hljs-variable">c</span>: (<span class="hljs-variable">name</span>: <span class="hljs-title class_">String</span>, <span class="hljs-keyword">Int64</span>) = (<span class="hljs-string">"banana"</span>, <span class="hljs-number">5</span>) <span class="hljs-comment">// Error</span></li></ol></pre> </div> </div> <div></div></div> ### 数组类型 <div _ngcontent-apy-c173="" class="markdown-body ng-star-inserted" style="position: relative;"> <div id="body486378825144659"> <div class="tiledSection"><h2 id="array">Array<i class="anchorIcon" anchorid="array" tips="复制节点链接"></i></h2><p id="ZH-CN_TOPIC_0000002084257257__p2104973287144659">我们可以使用 Array 类型来构造单一元素类型,有序序列的数据。</p> <p id="ZH-CN_TOPIC_0000002084257257__p1139152507144659">仓颉使用 Array<T> 来表示 Array 类型。T 表示 Array 的元素类型,T 可以是任意类型。</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002084257257__screen735056019144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">var</span> <span class="hljs-variable">a</span>: <span class="hljs-title class_">Array</span><<span class="hljs-keyword">Int64</span>> = ... <span class="hljs-comment">// Array whose element type is Int64</span></li><li><span class="hljs-keyword">var</span> <span class="hljs-variable">b</span>: <span class="hljs-title class_">Array</span><<span class="hljs-title class_">String</span>> = ... <span class="hljs-comment">// Array whose element type is String</span></li></ol></pre> <p id="ZH-CN_TOPIC_0000002084257257__p1448873404144659">元素类型不相同的 Array 是不相同的类型,所以它们之间不可以互相赋值。</p> <p id="ZH-CN_TOPIC_0000002084257257__p174211895144659">因此以下例子是不合法的。</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002084257257__screen1405983203144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-variable">b</span> = <span class="hljs-variable">a</span> <span class="hljs-comment">// Type mismatch</span></li></ol></pre> <p id="ZH-CN_TOPIC_0000002084257257__p320872318144659">我们可以轻松使用字面量来初始化一个 Array,只需要使用方括号将逗号分隔的值列表括起来即可。</p> <p id="ZH-CN_TOPIC_0000002084257257__p463997424144659">编译器会根据上下文自动推断 Array 字面量的类型。</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002084257257__screen532857857144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">let</span> <span class="hljs-variable">a</span>: <span class="hljs-title class_">Array</span><<span class="hljs-title class_">String</span>> = [] <span class="hljs-comment">// Created an empty Array whose element type is String</span></li><li><span class="hljs-keyword">let</span> <span class="hljs-variable">b</span> = [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">3</span>, <span class="hljs-number">2</span>, <span class="hljs-number">1</span>] <span class="hljs-comment">// Created a Array whose element type is Int64, containing elements 1, 2, 3, 3, 2, 1</span></li></ol></pre> <p id="ZH-CN_TOPIC_0000002084257257__p493154187144659">也可以使用构造函数的方式构造一个指定元素类型的 Array。</p> <p id="ZH-CN_TOPIC_0000002084257257__p1489293248144659">需要注意的是,当通过 item 指定的初始值初始化 Array 时,该构造函数不会拷贝 item,如果 item 是一个引用类型,构造后数组的每一个元素都将指向相同的引用。</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002084257257__screen912771236144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">let</span> <span class="hljs-variable">a</span> = <span class="hljs-title class_">Array</span><<span class="hljs-keyword">Int64</span>>() <span class="hljs-comment">// Created an empty Array whose element type is Int64</span></li><li><span class="hljs-keyword">let</span> <span class="hljs-variable">b</span> = <span class="hljs-title class_">Array</span><<span class="hljs-keyword">Int64</span>>(<span class="hljs-variable">a</span>) <span class="hljs-comment">// Use another Array to initialize b</span></li><li><span class="hljs-keyword">let</span> <span class="hljs-variable">c</span> = <span class="hljs-title class_">Array</span><<span class="hljs-keyword">Int64</span>>(<span class="hljs-number">3</span>, <span class="hljs-variable">item</span>: <span class="hljs-number">0</span>) <span class="hljs-comment">// Created an Array whose element type is Int64, length is 3 and all elements are initialized as 0</span></li><li><span class="hljs-keyword">let</span> <span class="hljs-variable">d</span> = <span class="hljs-title class_">Array</span><<span class="hljs-keyword">Int64</span>>(<span class="hljs-number">3</span>, {<span class="hljs-variable">i</span> => <span class="hljs-variable">i</span> + <span class="hljs-number">1</span>}) <span class="hljs-comment">// Created an Array whose element type is Int64, length is 3 and all elements are initialized by the initialization function</span></li></ol></pre> <p id="ZH-CN_TOPIC_0000002084257257__p1023659231144659">示例中 let d = Array<Int64>(3, {i => i + 1}) 使用了 <a href="https://developer.huawei.com/consumer/cn/doc/cangjie-guides-V5/lambda-V5">lambda 表达式</a>作为初始化函数来初始化数组中的每一个元素,即 {i => i + 1}。</p> </div> <div class="tiledSection"><h3 id="访问-array-成员" class="firsth2">访问 Array 成员<i class="anchorIcon" anchorid="访问-array-成员" tips="复制节点链接"></i></h3><p id="ZH-CN_TOPIC_0000002084257257__p1729943813144659">当我们需要对 Array 的所有元素进行访问时,可以使用 for-in 循环遍历 Array 的所有元素。</p> <p id="ZH-CN_TOPIC_0000002084257257__p1241726828144659">Array 是按元素插入顺序排列的,因此对 Array 遍历的顺序总是恒定的。</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002084257257__screen15516798144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">main</span>() {</li><li> <span class="hljs-keyword">let</span> <span class="hljs-variable">arr</span> = [<span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">2</span>]</li><li> <span class="hljs-keyword">for</span> (<span class="hljs-variable">i</span> <span class="hljs-keyword">in</span> <span class="hljs-variable">arr</span>) {</li><li> <span class="hljs-title function_">println</span>(<span class="hljs-string">"The element is <span class="hljs-subst">${<span class="hljs-variable">i</span>}</span>"</span>)</li><li> }</li><li>}</li></ol></pre> <p id="ZH-CN_TOPIC_0000002084257257__p817966715144659">编译并执行上面的代码,会输出:</p> <pre class="text prettyprint linenums hljs language-plaintext" id="ZH-CN_TOPIC_0000002084257257__screen443039293144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li>The element is 0</li><li>The element is 1</li><li>The element is 2</li></ol></pre> <p id="ZH-CN_TOPIC_0000002084257257__p751186760144659">当我们需要知道某个 Array 包含的元素个数时,可以使用 size 属性获得对应信息。</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002084257257__screen1332875209144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">main</span>() {</li><li> <span class="hljs-keyword">let</span> <span class="hljs-variable">arr</span> = [<span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">2</span>]</li><li> <span class="hljs-keyword">if</span> (<span class="hljs-variable">arr</span>.<span class="hljs-variable">size</span> == <span class="hljs-number">0</span>) {</li><li> <span class="hljs-title function_">println</span>(<span class="hljs-string">"This is an empty array"</span>)</li><li> } <span class="hljs-keyword">else</span> {</li><li> <span class="hljs-title function_">println</span>(<span class="hljs-string">"The size of array is <span class="hljs-subst">${<span class="hljs-variable">arr</span>.<span class="hljs-variable">size</span>}</span>"</span>)</li><li> }</li><li>}</li></ol></pre> <p id="ZH-CN_TOPIC_0000002084257257__p1112199530144659">编译并执行上面的代码,会输出:</p> <pre class="text prettyprint linenums hljs language-plaintext" id="ZH-CN_TOPIC_0000002084257257__screen980713693144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li>The size of array is 3</li></ol></pre> <p id="ZH-CN_TOPIC_0000002084257257__p268365785144659">当我们想访问单个指定位置的元素时,可以使用下标语法访问(下标的类型必须是 Int64)。非空 Array 的第一个元素总是从位置 0 开始的。我们可以从 0 开始访问 Array 的任意一个元素,直到最后一个位置(Array 的 size - 1)。索引值不能使用负数或者大于等于 size,当编译器能检查出索引值非法时,会在编译时报错,否则会在运行时抛异常。</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002084257257__screen1100598860144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">main</span>() {</li><li> <span class="hljs-keyword">let</span> <span class="hljs-variable">arr</span> = [<span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">2</span>]</li><li> <span class="hljs-keyword">let</span> <span class="hljs-variable">a</span> = <span class="hljs-variable">arr</span>[<span class="hljs-number">0</span>] <span class="hljs-comment">// a == 0</span></li><li> <span class="hljs-keyword">let</span> <span class="hljs-variable">b</span> = <span class="hljs-variable">arr</span>[<span class="hljs-number">1</span>] <span class="hljs-comment">// b == 1</span></li><li> <span class="hljs-keyword">let</span> <span class="hljs-variable">c</span> = <span class="hljs-variable">arr</span>[-<span class="hljs-number">1</span>] <span class="hljs-comment">// array size is '3', but access index is '-1', which would overflow</span></li><li>}</li></ol></pre> <p id="ZH-CN_TOPIC_0000002084257257__p1296786425144659">如果我们想获取某一段 Array 的元素,可以在下标中传入 Range 类型的值,就可以一次性取得 Range 对应范围的一段 Array。</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002084257257__screen559021858144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">let</span> <span class="hljs-variable">arr1</span> = [<span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>, <span class="hljs-number">6</span>]</li><li><span class="hljs-keyword">let</span> <span class="hljs-variable">arr2</span> = <span class="hljs-variable">arr1</span>[<span class="hljs-number">0</span>..<span class="hljs-number">5</span>] <span class="hljs-comment">// arr2 contains the elements 0, 1, 2, 3, 4</span></li></ol></pre> <p id="ZH-CN_TOPIC_0000002084257257__p1840589197144659">当 Range 字面量在下标语法中使用时,我们可以省略 start 或 end。</p> <p id="ZH-CN_TOPIC_0000002084257257__p1909660039144659">当省略 start 时,Range 会从 0 开始;当省略 end 时,Range 的 end 会延续到最后一位。</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002084257257__screen893509683144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">let</span> <span class="hljs-variable">arr1</span> = [<span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>, <span class="hljs-number">6</span>]</li><li><span class="hljs-keyword">let</span> <span class="hljs-variable">arr2</span> = <span class="hljs-variable">arr1</span>[..<span class="hljs-number">3</span>] <span class="hljs-comment">// arr2 contains elements 0, 1, 2</span></li><li><span class="hljs-keyword">let</span> <span class="hljs-variable">arr3</span> = <span class="hljs-variable">arr1</span>[<span class="hljs-number">2</span>..] <span class="hljs-comment">// arr3 contains elements 2, 3, 4, 5, 6</span></li></ol></pre> </div> <div class="tiledSection"><h3 id="修改-array">修改 Array<i class="anchorIcon" anchorid="修改-array" tips="复制节点链接"></i></h3><p id="ZH-CN_TOPIC_0000002084257257__p1762993992144659">Array 是一种长度不变的 Collection 类型,因此 Array 没有提供添加和删除元素的成员函数。</p> <p id="ZH-CN_TOPIC_0000002084257257__p1841704363144659">但是 Array 允许我们对其中的元素进行修改,同样使用下标语法。</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002084257257__screen1072292909144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">main</span>() {</li><li> <span class="hljs-keyword">let</span> <span class="hljs-variable">arr</span> = [<span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>]</li><li> <span class="hljs-variable">arr</span>[<span class="hljs-number">0</span>] = <span class="hljs-number">3</span></li><li> <span class="hljs-title function_">println</span>(<span class="hljs-string">"The first element is <span class="hljs-subst">${<span class="hljs-variable">arr</span>[<span class="hljs-number">0</span>]}</span>"</span>)</li><li>}</li></ol></pre> <p id="ZH-CN_TOPIC_0000002084257257__p310810279144659">编译并执行上面的代码,会输出:</p> <pre class="text prettyprint linenums hljs language-plaintext" id="ZH-CN_TOPIC_0000002084257257__screen1113040851144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li>The first element is 3</li></ol></pre> <p id="ZH-CN_TOPIC_0000002084257257__p284088841144659">Array 是引用类型,因此 Array 在作为表达式使用时不会拷贝副本,同一个 Array 实例的所有引用都会共享同样的数据。</p> <p id="ZH-CN_TOPIC_0000002084257257__p1709881827144659">因此对 Array 元素的修改会影响到该实例的所有引用。</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002084257257__screen1865139341144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">let</span> <span class="hljs-variable">arr1</span> = [<span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">2</span>]</li><li><span class="hljs-keyword">let</span> <span class="hljs-variable">arr2</span> = <span class="hljs-variable">arr1</span></li><li><span class="hljs-variable">arr2</span>[<span class="hljs-number">0</span>] = <span class="hljs-number">3</span></li><li><span class="hljs-comment">// arr1 contains elements 3, 1, 2</span></li><li><span class="hljs-comment">// arr2 contains elements 3, 1, 2</span></li></ol></pre> </div> <div class="tiledSection"><h2 id="varray">VArray<i class="anchorIcon" anchorid="varray" tips="复制节点链接"></i></h2><p id="ZH-CN_TOPIC_0000002084257257__p1463323646144659">除了引用类型的数组 Array,仓颉还引入了值类型数组 VArray<T, $N> ,其中 T 表示该值类型数组的元素类型,$N 是一个固定的语法,通过 $ 加上一个 Int64 类型的数值字面量表示这个值类型数组的长度。需要注意的是,VArray<T, $N> 不能省略 <T, $N>,且使用类型别名时,不允许拆分 VArray 关键字与其泛型参数。</p> <p id="ZH-CN_TOPIC_0000002084257257__p377582166144659">与频繁使用引用类型 Array 相比,使用值类型 VArray 可以减少堆上内存分配和垃圾回收的压力。但是需要注意的是,由于值类型本身在传递和赋值时的拷贝,会产生额外的性能开销,因此建议不要在性能敏感场景使用较大长度的 VArray。值类型和引用类型的特点可以参考<a href="https://developer.huawei.com/consumer/cn/doc/cangjie-guides-V5/program_structure-V5#值类型和引用类型变量">值类型和引用类型变量</a>。</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002084257257__screen1174377649144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">type</span> <span class="hljs-title class_">varr1</span> = <span class="hljs-keyword">VArray</span><<span class="hljs-keyword">Int64</span>, $<span class="hljs-number">3</span>> <span class="hljs-comment">// Ok</span></li><li><span class="hljs-keyword">type</span> <span class="hljs-title class_">varr2</span> = <span class="hljs-keyword">VArray</span> <span class="hljs-comment">// Error</span></li></ol></pre> <div><div class="hw-editor-tip warn"><div class="title">注意</div><div class="content"> <p id="ZH-CN_TOPIC_0000002084257257__p268474959144659">由于运行时后端限制,当前 VArray<T, $N> 的元素类型 T 或 T 的成员不能包含引用类型、枚举类型、Lambda 表达式(CFunc 除外)以及未实例化的泛型类型。</p> </div></div></div> <p id="ZH-CN_TOPIC_0000002084257257__p2037802142144659">VArray 可以由一个数组的字面量来进行初始化,左值 a 必须标识出 VArray 的实例化类型:</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002084257257__screen1413914914144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">var</span> <span class="hljs-variable">a</span>: <span class="hljs-keyword">VArray</span><<span class="hljs-keyword">Int64</span>, $<span class="hljs-number">3</span>> = [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>]</li></ol></pre> <p id="ZH-CN_TOPIC_0000002084257257__p486995022144659">同时,它拥有两个构造函数:</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002084257257__screen118274183144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-comment">// VArray<T, $N>(initElement: (Int64) -> T)</span></li><li><span class="hljs-keyword">let</span> <span class="hljs-variable">b</span> = <span class="hljs-keyword">VArray</span><<span class="hljs-keyword">Int64</span>, $<span class="hljs-number">5</span>>({ <span class="hljs-variable">i</span> => <span class="hljs-variable">i</span>}) <span class="hljs-comment">// [0, 1, 2, 3, 4]</span></li><li><span class="hljs-comment">// VArray<T, $N>(item!: T)</span></li><li><span class="hljs-keyword">let</span> <span class="hljs-variable">c</span> = <span class="hljs-keyword">VArray</span><<span class="hljs-keyword">Int64</span>, $<span class="hljs-number">5</span>>(<span class="hljs-variable">item</span>: <span class="hljs-number">0</span>) <span class="hljs-comment">// [0, 0, 0, 0, 0]</span></li></ol></pre> <p id="ZH-CN_TOPIC_0000002084257257__p1998844067144659">除此之外,VArray<T, $N> 类型提供了两个成员方法:</p> <ul id="ZH-CN_TOPIC_0000002084257257__ul624396114144659"><li id="li1058957308144659"><p id="ZH-CN_TOPIC_0000002084257257__p1131758598144659">用于下标访问和修改的 [] 操作符方法:</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002084257257__screen11053412144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">var</span> <span class="hljs-variable">a</span>: <span class="hljs-keyword">VArray</span><<span class="hljs-keyword">Int64</span>, $<span class="hljs-number">3</span>> = [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>]</li><li><span class="hljs-keyword">let</span> <span class="hljs-variable">i</span> = <span class="hljs-variable">a</span>[<span class="hljs-number">1</span>] <span class="hljs-comment">// i is 2</span></li><li><span class="hljs-variable">a</span>[<span class="hljs-number">2</span>] = <span class="hljs-number">4</span> <span class="hljs-comment">// a is [1, 2, 4]</span></li></ol></pre> <p id="ZH-CN_TOPIC_0000002084257257__p931442420144659">下标访问的下标类型必须为 Int64。</p> </li><li id="li1752224211144659"><p id="ZH-CN_TOPIC_0000002084257257__p1285990869144659">用于获取 VArray 长度的 size 成员:</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002084257257__screen1375578569144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">var</span> <span class="hljs-variable">a</span>: <span class="hljs-keyword">VArray</span><<span class="hljs-keyword">Int64</span>, $<span class="hljs-number">3</span>> = [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>]</li><li><span class="hljs-keyword">let</span> <span class="hljs-variable">s</span> = <span class="hljs-variable">a</span>.<span class="hljs-variable">size</span> <span class="hljs-comment">// s is 3</span></li></ol></pre> <p id="ZH-CN_TOPIC_0000002084257257__p1780099062144659">size 属性的类型为 Int64。</p> </li></ul> <p id="ZH-CN_TOPIC_0000002084257257__p1410020125144659">此外,VArray 还支持仓颉与 C 语言互操作场景使用,相关内容可以参考<a href="https://developer.huawei.com/consumer/cn/doc/cangjie-guides-V5/cangjie-c-V5#数组">数组</a>。</p> </div> </div> <div></div></div> ### 区间类型 <div _ngcontent-apy-c173="" class="markdown-body ng-star-inserted" style="position: relative;"> <div id="body235890230144659"><p id="ZH-CN_TOPIC_0000002048139780__p929316203144659">区间类型用于表示拥有固定步长的序列,区间类型是一个泛型(详见<a href="https://developer.huawei.com/consumer/cn/doc/cangjie-guides-V5/generic_overview-V5">泛型</a>章节),使用 Range<T> 表示。当 T 被实例化不同的类型时(要求此类型必须支持关系操作符,并且可以和 Int64 类型的值做加法),会得到不同的区间类型,如最常用的 Range<Int64> 用于表示整数区间。</p> <p id="ZH-CN_TOPIC_0000002048139780__p61180214144659">每个区间类型的实例都会包含 start、end 和 step 三个值。其中,start 和 end 分别表示序列的起始值和终止值,step 表示序列中前后两个元素之间的差值(即步长);start 和 end 的类型相同(即 T 被实例化的类型),step 类型是 Int64,并且它的值不能等于 0。</p> <p id="ZH-CN_TOPIC_0000002048139780__p155411125144659">下面的例子给出了区间类型的实例化方式(关于区间类型定义和其中的属性,详见《仓颉编程语言库 API》):</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002048139780__screen823223398144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-comment">// Range<T>(start: T, end: T, step: Int64, hasStart: Bool, hasEnd: Bool, isClosed: Bool)</span></li><li><span class="hljs-keyword">let</span> <span class="hljs-variable">r1</span> = <span class="hljs-title class_">Range</span><<span class="hljs-keyword">Int64</span>>(<span class="hljs-number">0</span>, <span class="hljs-number">10</span>, <span class="hljs-number">1</span>, <span class="hljs-keyword">true</span>, <span class="hljs-keyword">true</span>, <span class="hljs-keyword">true</span>) <span class="hljs-comment">// r1 contains 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10</span></li><li><span class="hljs-keyword">let</span> <span class="hljs-variable">r2</span> = <span class="hljs-title class_">Range</span><<span class="hljs-keyword">Int64</span>>(<span class="hljs-number">0</span>, <span class="hljs-number">10</span>, <span class="hljs-number">1</span>, <span class="hljs-keyword">true</span>, <span class="hljs-keyword">true</span>, <span class="hljs-keyword">false</span>) <span class="hljs-comment">// r2 contains 0, 1, 2, 3, 4, 5, 6, 7, 8, 9</span></li><li><span class="hljs-keyword">let</span> <span class="hljs-variable">r3</span> = <span class="hljs-title class_">Range</span><<span class="hljs-keyword">Int64</span>>(<span class="hljs-number">10</span>, <span class="hljs-number">0</span>, -<span class="hljs-number">2</span>, <span class="hljs-keyword">true</span>, <span class="hljs-keyword">true</span>, <span class="hljs-keyword">false</span>) <span class="hljs-comment">// r3 contains 10, 8, 6, 4, 2</span></li></ol></pre> <div class="tiledSection"><h2 id="区间类型字面量">区间类型字面量<i class="anchorIcon" anchorid="区间类型字面量" tips="复制节点链接"></i></h2><p id="ZH-CN_TOPIC_0000002048139780__p672555960144659">区间字面量有两种形式:“左闭右开”区间和“左闭右闭”区间。</p> <ul id="ZH-CN_TOPIC_0000002048139780__ul1308187786144659"><li id="li1856219513144659">“左闭右开”区间的格式是 start..end : step,它表示一个从 start 开始,以 step 为步长,到 end(不包含 end)为止的区间;</li><li id="li1752786181144659">“左闭右闭”区间的格式是 start..=end : step,它表示一个从 start 开始,以 step 为步长,到 end(包含 end)为止的区间。</li></ul> <p id="ZH-CN_TOPIC_0000002048139780__p1876136508144659">下面的例子定义了若干区间类型的变量:</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002048139780__screen404278651144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">let</span> <span class="hljs-variable">n</span> = <span class="hljs-number">10</span></li><li><span class="hljs-keyword">let</span> <span class="hljs-variable">r1</span> = <span class="hljs-number">0</span>..<span class="hljs-number">10</span> : <span class="hljs-number">1</span> <span class="hljs-comment">// r1 contains 0, 1, 2, 3, 4, 5, 6, 7, 8, 9</span></li><li><span class="hljs-keyword">let</span> <span class="hljs-variable">r2</span> = <span class="hljs-number">0</span>..=<span class="hljs-variable">n</span> : <span class="hljs-number">1</span> <span class="hljs-comment">// r2 contains 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10</span></li><li><span class="hljs-keyword">let</span> <span class="hljs-variable">r3</span> = <span class="hljs-variable">n</span>..<span class="hljs-number">0</span> : -<span class="hljs-number">2</span> <span class="hljs-comment">// r3 contains 10, 8, 6, 4, 2</span></li><li><span class="hljs-keyword">let</span> <span class="hljs-variable">r4</span> = <span class="hljs-number">10</span>..=<span class="hljs-number">0</span> : -<span class="hljs-number">2</span> <span class="hljs-comment">// r4 contains 10, 8, 6, 4, 2, 0</span></li></ol></pre> <p id="ZH-CN_TOPIC_0000002048139780__p1083462234144659">区间字面量中,可以不写 step,此时 step 默认等于 1,但是注意,step 的值不能等于 0。另外,区间也有可能是空的(即不包含任何元素的空序列),举例如下:</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002048139780__screen1977294423144659" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">let</span> <span class="hljs-variable">r5</span> = <span class="hljs-number">0</span>..<span class="hljs-number">10</span> <span class="hljs-comment">// the step of r5 is 1, and it contains 0, 1, 2, 3, 4, 5, 6, 7, 8, 9</span></li><li><span class="hljs-keyword">let</span> <span class="hljs-variable">r6</span> = <span class="hljs-number">0</span>..<span class="hljs-number">10</span> : <span class="hljs-number">0</span> <span class="hljs-comment">// Error, step cannot be 0</span></li><li> </li><li><span class="hljs-keyword">let</span> <span class="hljs-variable">r7</span> = <span class="hljs-number">10</span>..<span class="hljs-number">0</span> : <span class="hljs-number">1</span> <span class="hljs-comment">// r7 to r10 are empty ranges</span></li><li><span class="hljs-keyword">let</span> <span class="hljs-variable">r8</span> = <span class="hljs-number">0</span>..<span class="hljs-number">10</span> : -<span class="hljs-number">1</span></li><li><span class="hljs-keyword">let</span> <span class="hljs-variable">r9</span> = <span class="hljs-number">10</span>..=<span class="hljs-number">0</span> : <span class="hljs-number">1</span></li><li><span class="hljs-keyword">let</span> <span class="hljs-variable">r10</span> = <span class="hljs-number">0</span>..=<span class="hljs-number">10</span> : -<span class="hljs-number">1</span></li></ol></pre> <div><div class="hw-editor-tip warn"><div class="title">注意</div><div class="content"> <ul id="ZH-CN_TOPIC_0000002048139780__ul2075647796144659"><li id="li1091316705144659">表达式 start..end : step 中,当 step > 0 且 start >= end,或者 step < 0 且 start <= end 时,start..end : step 是一个空区间;</li><li id="li1507560369144659">表达式 start..=end : step 中,当 step > 0 且 start > end,或者 step < 0 且 start < end 时,start..=end : step 是一个空区间。</li></ul> </div></div></div> </div> </div> <div></div></div> ### Unit 类型 <div _ngcontent-apy-c173="" class="markdown-body ng-star-inserted" style="position: relative;"> <div id="body1233843692144700"><p id="ZH-CN_TOPIC_0000002084338685__p734796387144700">对于那些只关心副作用而不关心值的表达式,它们的类型是 Unit。例如,print 函数、赋值表达式、复合赋值表达式、自增和自减表达式、循环表达式,它们的类型都是 Unit。</p> <p id="ZH-CN_TOPIC_0000002084338685__p1835430228144700">Unit 类型只有一个值,也是它的字面量:()。除了赋值、判等和判不等外,Unit 类型不支持其他操作。</p> </div> <div></div></div> ### Nothing 类型 <div _ngcontent-apy-c173="" class="markdown-body ng-star-inserted" style="position: relative;"> <div id="body275942614144700"><p id="ZH-CN_TOPIC_0000002048298044__p1441713208144700">Nothing 是一种特殊的类型,它不包含任何值,并且 Nothing 类型是所有类型的子类型。</p> <p id="ZH-CN_TOPIC_0000002048298044__p940697095144700">break、continue、return 和 throw 表达式的类型是 Nothing,程序执行到这些表达式时,它们之后的代码将不会被执行。其中 break、continue 只能在循环体中使用,return 只能在函数体中使用。</p> <p id="ZH-CN_TOPIC_0000002048298044__p531455307144700">包围着的循环体“无法穿越”函数边界。在下面的例子中,break 出现在函数 f 中,外层的 while 循环体不被视作包围着它的循环体;continue 出现在 lambda 表达式中,外层的 while 循环体不被视作包围着它的循环体。</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002048298044__screen1949823049144700" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">while</span> (<span class="hljs-keyword">true</span>) {</li><li> <span class="hljs-keyword">func</span> <span class="hljs-title function_">f</span>() {</li><li> <span class="hljs-keyword">break</span> <span class="hljs-comment">// Error, break must be used directly inside a loop</span></li><li> }</li><li> <span class="hljs-keyword">let</span> <span class="hljs-variable">g</span> = { =></li><li> <span class="hljs-keyword">continue</span> <span class="hljs-comment">// Error, continue must be used directly inside a loop</span></li><li> }</li><li>}</li></ol></pre> <p id="ZH-CN_TOPIC_0000002048298044__p1958492706144700">由于函数的形参和其默认值不属于该函数的函数体,所以下面例子中的 return 表达式缺少包围它的函数体——它既不属于外层函数 f(因为内层函数定义 g 已经开始),也不在内层函数 g 的函数体中:</p> <pre class="cangjie prettyprint linenums hljs language-cangjie" id="ZH-CN_TOPIC_0000002048298044__screen1403155531144700" data-highlighted="yes"><div class="sun"></div><div class="copySuc" style="display: none;">已复制</div><div class="copybtn"></div><ol class="linenums"><li><span class="hljs-keyword">func</span> <span class="hljs-title function_">f</span>() {</li><li> <span class="hljs-keyword">func</span> <span class="hljs-title function_">g</span>(<span class="hljs-variable">x</span>!: <span class="hljs-keyword">Int64</span> = <span class="hljs-keyword">return</span>) { <span class="hljs-comment">// Error, return must be used inside a function body</span></li><li> <span class="hljs-number">0</span></li><li> }</li><li> <span class="hljs-number">1</span></li><li>}</li></ol></pre> <div><div class="hw-editor-tip warn"><div class="title">注意</div><div class="content"> <p id="ZH-CN_TOPIC_0000002048298044__p2049341699144700">目前编译器还不允许在使用类型的地方显式地使用 Nothing 类型。</p> </div></div></div> </div> <div></div></div>
admin
2024年11月8日 17:24
转发文档
收藏文档
上一篇
下一篇
手机扫码
复制链接
手机扫一扫转发分享
复制链接
Markdown文件
分享
链接
类型
密码
更新密码