华为仓颉编程语言的表达式及其特点
华为仓颉编程语言的表达式及其特点
仓颉(Cangjie)语言的表达式有一个明显的特点,范围不再局限于传统算术运算,而是扩展到条件表达式、循环表达式等多种类型,每种表达式均有确定的类型和值。
传统基本表达式,由一个或多个操作数(operand)通过零个或多个操作符(operator)组合而成如 a + 10(假设a和b为已定义的数值变量)。字面量是直接表示值的表达式如 42、\"Hello\"。
表达式总是隐含着一个计算过程,因此每个表达式都会有一个计算结果。对于只有操作数而没有操作符的表达式,其计算结果就是操作数自身。
本文不多介绍传统基本表达式,下面重点介绍控制流表达式。
仓颉(Cangjie)作为一门融合了现代编程语言设计理念的语言,弱化了传统 “语句” 与 “表达式” 的界限:
• 条件分支 → if-else 表达式
• 循环 → while、for 表达式
• 异常处理 → try 表达式
• 控制转移 → break、continue 也是表达式,类型为 Nothing
这体现了该语言将传统控制结构表达式化的设计理念。但需要特别注意在这方面的差异化处置:
【仅就目前( 2025 年 7 月推出首个长期支持版本(LTS 1.0.0)),华为仓颉编程语言,在传统控制结构表达式化这方面的差异化处置的总结】
if-else 表达式的类型(返回值类型)由分支类型推断(可能是任意类型,包括 Unit 或非 Unit——指的是它们通常用于返回一个有意义的值(如 String
、Int
等)。
while、do-while、for 表达式类型(返回值类型)都是 Unit,强调副作用而非返回值。和if-else 表达式不同,仓颉编程语言的while、do-while、for 表达式类型都是 Unit(表示 “无实际值” 的空类型),强调副作用而非返回值。
Unit:表示“有操作但无值”,类型安全且可显式使用。
【唯一值:Unit 类型只有一个实例,即 ()(空元组)。它不携带任何数据,仅表示“操作已完成,但无有意义的结果”。
类型安全:与直接忽略返回值不同,仓颉强制要求显式处理 Unit 类型,避免隐式丢弃值导致的潜在错误。】
异常处理 try 表达式返回值可能为非 Unit 类型。
break 和 continue 表达式的类型(返回值类型)为 Nothing,表示它们不返回任何值且不会改变程序的控制流之外的状态。
Nothing:表示“无可能返回”(如 break/continue/抛出异常),是所有类型的子类型,用于控制流转移。
刚开始不太好懂,先总体了解之,看完下面展开介绍及例子,就会逐渐明了。
如何运行下面代码,可参见
华为仓颉编程语言简介与快速实验上手图解_仓颉1.0.0示例-CSDN博客
华为仓颉编程语言实践体验-CSDN博客
if-else 表达式
基本形式:
if (条件) {
分支 1
} else {
分支 2
}
也可写为:
if (条件) { 分支1 } else { 分支2 }。
例如:
import std.convert.*main() { print(\"请输入score的值: \") var str: String = readln() var score = Int8.parse(str) // if-else 示例 if (score >= 60) { println(\"及格\") } else { println(\"不及格\") } }
测试运行:
特别说明
if-else 表达式的类型由分支类型推断(可能是任意类型,包括 Unit 或非 Unit)。求值规则:
计算“条件”表达式的值,若为 true,则执行“分支1”;若为 false 且存在 else 分支,则执行“分支2”。例如:
import std.convert.*main() { print(\"请输入a的值: \") var str: String = readln() var a = Int64.parse(str) print(\"请输入b的值: \") var str2: String = readln() var b = Int64.parse(str2) println(\"max = ${if (a >= b) { a } else { b }}\") //注意这一句,相当于下面两句 let max = if (a >= b) { a } else { b } //注意这一句 println(\"max = ${max}\")}
测试运行
循环:while、do-while、for 表达式
while、do-while、for 表达式的类型都是 Unit,强调副作用而非返回值。后面以for 表达式为例特别说明。
while 表达式
基本形式
while (条件) {
循环体
}
例如:
main() { var i = 0 var sum = 0 while (i < 10) { // 调整条件,确保累加1~10 i += 1 sum += i } println(\"输出: sum = ${sum}\") //输出: sum = 55 return 0}
do-while 表达式
基本形式:
do {
循环体
} while (条件)
例如:
main() { var i = 1 do { println(\"Current value: ${i}\") i += 1 } while (i <= 3) }
输出:
Current value: 1
Current value: 2
Current value: 3
for-in 表达式
基本形式:
for (迭代变量 in 序列) {
循环体
}
例如
main() { var sum = 0 for (i in 1..=100) { sum += i } println(\"sum = ${sum}\") //sum = 5050}
前面提到while、do-while、for 表达式类型都是 Unit,强调副作用而非返回值。什么意思?for 循环表达式为例说明,请看下面例子:
main() { var sum = 0 println(\"sum = ${for (i in 1..=100) { sum += i }}\")}
你可能想,预期通过 for 循环表达式计算 1 + 2 + ... + 100 的和(5050),然后通过字符串模板 ${...} 输出 sum = 5050。
但是实际输出sum = (),而不是sum = 5050 ,问什么?
解释:
for循环作为表达式,其默认返回值类型是Unit(表示 “无实际值” 的空类型),无论循环体内做了什么操作。
代码中for (i in 1..=100) { sum += i }的作用是修改外部变量sum(这是一种 “副作用”),但循环本身的返回值始终是Unit。
当你在字符串模板中使用${for (...) {}}时,实际插入的是Unit类型的默认表示形式(),因此输出sum = ()。
你打印的是循环表达式的返回值(Unit),而不是sum变量的值。要打印sum变量的值,可参见前面的示例。
异常处理:try 表达式
基本形式:
try {
// 可能出现异常的代码
} catch (e: ExceptionType) {
// 处理异常的代码
} finally {
// 资源释放的代码(可选)
}
try 块:执行可能抛出异常的代码。
catch 块:捕获异常并返回一个备用值(确保表达式始终有返回值)。
finally 块(可选):执行清理操作,但不影响 try 表达式的返回值。
例、判断用户给出的整数的奇偶性,用try异常处理,防止用户输入非数字将出错中断运行,源码如下:
import std.convert.*import std.io.* main(){ print(\"请输入一个整数:\") while (true) { var str: String = readln() if (str.isEmpty()) { print(\"输入为空,请重新输入一个整数:\") continue } // 使用 try-catch 捕获 parse 可能抛出的异常 try { var n = Int64.parse(str) if( n % 2 == 0) { println(\"${n} 是偶数\") } else { println(\"${n} 是奇数\") } break } catch(e:IllegalArgumentException){ print(\"输入非法,请输入一个有效的整数:\") } } }
特别提示
异常处理 try 表达式返回值可能为非 Unit 类型
在华为仓颉编程语言中,try 表达式的返回值类型由 try 块或 catch 块中的最后一行表达式决定。若这些分支返回非 Unit 类型的值,则整个 try 表达式的类型会推断为该具体类型。
例如:
main() { // 示例1:try和catch都返回Int类型 let result1 = try { let x = 10 let y = 2 x / y // 返回Int } catch (e: Exception) { println(\"发生错误: ${e.message}\") 0 // 返回Int } println(\"结果1: ${result1}\") // 输出: 结果1: 5 // 示例2:try返回String,catch返回String let result2 = try { \"成功执行\" // 返回String } catch (e: Exception) { \"执行失败\" // 返回String } println(\"结果2: ${result2}\") // 输出: 结果2: 成功执行 // 示例3:try抛出异常,catch返回非Unit类型 let result3 = try { throw Exception(\"故意抛出异常\") //println(\"不会执行到这里\") } catch (e: Exception) { \"捕获到故意抛出异常\" // 返回String } println(\"结果3: ${result3}\") // 输出: 结果3: 捕获到异常}
测试运行:
这个示例展示了try表达式在不同情况下的返回值类型推断。当try或catch块最后一行是非Unit类型表达式时,整个try表达式就会采用该类型。
控制转移:break、continue 表达式
break 和 continue 表达式的类型为 Nothing,表示它们不返回任何值且不会改变程序的控制流之外的状态。
【Nothing 是一种特殊的类型,它不包含任何值,并且 Nothing 类型是所有类型的子类型(这当中也包括 Unit 类型)
break、continue、return 和 throw 表达式的类型是 Nothing,程序执行到这些表达式时,它们之后的代码将不会被执行。return 只能在函数体中使用,break、continue 只能在循环体中使用。】
例、以下程序使用 for-in 表达式和 break 表达式,在给定的整数数组中,找到第一个能被 5 整除的数字,源码如下:
main() { let numbers = [12, 18, 25, 36, 49, 55] for (number in numbers) { if (number % 5 == 0) { println(number) break } }}
例、以下程序使用 for-in 表达式和 continue 表达式,将给定整数数组中的奇数打印出来,源码如下:
main() { let numbers = [12, 18, 25, 36, 49, 55] for (number in numbers) { if (number % 2 == 0) { continue } println(number) }}输出:
输出:
25
49
55
赋值表达式
a= 2
b = a + 3
这些是是赋值表达式(包含赋值操作符的表达式),赋值表达式的类型是 Unit,值是 ()即空元组。例如:
main(){ var a = 1 var b = 2 println(\"${a}, ${b}\") /* a = (b = 0) // 编译错误,赋值表达式的类型是 Unit,值是 () if (a = 5) { // 编译错误,赋值表达式的类型是 Unit,值是 () } a = b = 0 // 语法错误,不支持链式使用赋值 */}
其中,// 符号之后写单行注释;一对 /* 和 */ 符号之间写多行注释。注释内容不影响程序的编译和运行。
附、官网介绍
https://cangjie-lang.cn/docs?url=%2F1.0.0%2Fuser_manual%2Fsource_zh_cn%2Fbasic_programming_concepts%2Fexpression.html
https://cangjie-lang.cn/docs?url=%2F1.0.0%2Fuser_manual%2Fsource_zh_cn%2Fbasic_data_type%2Fbasic_operators.html 见开头几段有相关赋值表达式的介绍