華為倉頡編程語言的表達式及其特點
倉頡(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~10i += 1sum += i }println("輸出: sum = ${sum}") //輸出: sum = 55return 0
}
do-while 表達式
基本形式:
do {
? 循環體
} while (條件)
例如:
main() {var i = 1do {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 = 0for (i in 1..=100) {sum += i}println("sum = ${sum}") //sum = 5050
}
前面提到while、do-while、for 表達式類型都是 Unit,強調副作用而非返回值。什么意思?for 循環表達式為例說明,請看下面例子:
main() {var sum = 0println("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 = 10let y = 2x / y // 返回Int} catch (e: Exception) {println("發生錯誤: ${e.message}")0 // 返回Int}println("結果1: ${result1}") // 輸出: 結果1: 5// 示例2:try返回String,catch返回Stringlet 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 = 1var b = 2println("${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=%2F0.53.18%2FSpec%2Fsource_zh_cn%2FChapter_12_Exceptions%28zh%29.html 中的“Try 表達式的類型”部分
https://cangjie-lang.cn/docs?url=%2F1.0.0%2Fuser_manual%2Fsource_zh_cn%2Fbasic_data_type%2Fbasic_operators.html 見開頭幾段有相關賦值表達式的介紹