重学仓颉-2基础编程概念详解

引言

仓颉语言(Cangjie Language)作为一门新兴的编程语言,具有强类型、函数式编程特性,并且支持现代化的编程范式。本文将深入探讨仓颉语言的基础编程概念,包括程序结构、标识符、函数定义和表达式系统。每个概念都将配有详细的代码示例,确保语法正确且可编译通过。

1. 程序结构(Program Structure)

1.1 基本概念

仓颉程序通常保存在扩展名为 .cj 的文本文件中。在顶层作用域中,可以定义全局变量、全局函数和自定义类型(如 structclassenuminterface)。程序入口是 main 函数,它可以有 Array<String> 类型的参数(用于接收命令行参数),也可以没有参数。

1.2 程序入口示例

cangjie 复制代码
package cangjie_blog
// 全局变量,最好有类型标注
let globalVariable: String = "Hello, Cangjie!"

// 全局函数
func globalFunction() {
    println("This is a global function")
}

// 自定义类型
struct MyStruct {
    MyStruct(let data: Int64){}
}

class MyClass {
    // 主构造函数,如果参数前面有修饰符,会自动生成同名的成员变量
     MyClass(let name: String){}
}

enum MyEnum {
    // 枚举值,用 | 分隔。
    // 第一个枚举值前面的|有可无
    | Case1 
    | Case2
    // 最后一个枚举值后面还可以有可选的 ...
    | ...
}

interface MyInterface {
    // 接口方法,不需要实现,只需要声明。必须明确参数和返回值类型
    func method(): Unit 
}

// 程序入口 - 不需要 func 修饰符
main() {
    println(globalVariable)
    globalFunction()
    
    let structInstance = MyStruct(42)
    let classInstance = MyClass("Cangjie")
    
    println("Struct data: ${structInstance.data}")
    println("Class name: ${classInstance.name}")
}

1.3 带命令行参数的程序入口

cangjie 复制代码
// args.cj
main(args: Array<String>) {
    println("程序名称: ${args[0]}")
    for (i in 1..args.size) {
        println("参数 ${i}: ${args[i]}")
    }
}

2. 标识符(Identifier)

2.1 标识符规则

仓颉语言的标识符分为普通标识符和原始标识符两类:

  • 普通标识符 :不能和仓颉关键字相同,必须以 XID_Start 字符开头,后接任意长度的 XID_Continue 字符,或者以一个 _ 开头,后接至少一个 XID_Continue 字符。
  • 原始标识符:在普通标识符或仓颉关键字的首尾加上一对反引号,主要用于将仓颉关键字作为标识符。

2.2 合法标识符示例

cangjie 复制代码
// valid_identifiers.cj
main() {
    // 普通标识符示例
    let abc = "普通英文标识符"
    let _abc = "下划线开头的标识符"
    let abc_ = "下划线结尾的标识符"
    let a1b2c3 = "包含数字的标识符"
    let a_b_c = "包含下划线的标识符"
    let 仓颉 = "中文字符标识符"
    let __こんにちは = "日文字符标识符"
    
    // 原始标识符示例
    let `abc1` = "原始标识符"
    let `if` = "关键字作为标识符"
    let `while` = "另一个关键字作为标识符"
    
    println(abc)
    println(_abc)
    println(abc_)
    println(a1b2c3)
    println(a_b_c)
    println(仓颉)
    println(__こんにちは)
    // 这里使用反引号引用abc这个变量。和直接使用abc是一样的
    println(`abc`)
    println(`abc1`)
    println(`if`)
    println(`while`)
}

2.3 非法标识符示例

cangjie 复制代码
// invalid_identifiers.cj
main() {
    // 以下代码会编译错误,仅用于演示非法标识符
    
    // let ab&c = "包含非法字符"  // 错误:& 不是 XID_Continue 字符
    // let 3abc = "数字开头"     // 错误:数字不能作为起始字符
    // let _ = "单独的下划线"    // 不会报错,但是也无法引用这个变量,相当于丢弃这个值。这里实际上是模式匹配语法
    // let while = "关键字"      // 错误:普通标识符不能使用关键字
    
    println("这些标识符都是非法的")
}

3. 函数(Function)

3.1 函数定义语法

仓颉语言使用关键字 func 来定义函数,语法格式为:

text 复制代码
func 函数名(参数列表): 返回值类型 {
    函数体
}

3.2 基本函数示例

cangjie 复制代码
// functions.cj

// 无参数无返回值的函数
func greet() {
    println("Hello, Cangjie!")
}

// 有参数无返回值的函数
func greetPerson(name: String) {
    println("Hello, ${name}!")
}

// 有参数有返回值的函数
func add(a: Int64, b: Int64): Int64 {
    return a + b
}

// 有多个返回值的函数(使用元组)
func divideAndRemainder(a: Int64, b: Int64): (Int64, Int64) {
    return (a / b, a % b)
}

// 递归函数示例
func factorial(n: Int64): Int64 {
    if (n <= 1) {
        return 1
    } else {
        return n * factorial(n - 1)
    }
}

main() {
    greet()
    greetPerson("张三")
    
    let sum = add(10, 20)
    println("10 + 20 = ${sum}")
    
    let (quotient, remainder) = divideAndRemainder(17, 5)
    println("17 ÷ 5 = ${quotient} 余 ${remainder}")
    
    let fact = factorial(5)
    println("5! = ${fact}")
}

3.3 函数重载示例

cangjie 复制代码
// function_overloading.cj

// 函数重载 - 不同参数类型
func add(a: Int64, b: Int64): Int64 {
    return a + b
}

func add(a: Float64, b: Float64): Float64 {
    return a + b
}

func add(a: String, b: String): String {
    return a + b
}

// 函数重载 - 不同参数数量
func multiply(a: Int64, b: Int64): Int64 {
    return a * b
}

func multiply(a: Int64, b: Int64, c: Int64): Int64 {
    return a * b * c
}

main() {
    println("整数相加: ${add(5, 3)}")
    println("浮点数相加: ${add(5.5, 3.2)}")
    println("字符串连接: ${add("Hello", " Cangjie")}")
    
    println("两个数相乘: ${multiply(4, 5)}")
    println("三个数相乘: ${multiply(2, 3, 4)}")
}

4. 变量(Variable)

4.1 变量定义

仓颉语言中的变量由变量名、数据类型、初始值和修饰符构成。主要修饰符包括:

  • let:不可变变量
  • var:可变变量
  • const:常量
  • private/public:可见性修饰符
  • static:静态性修饰符

4.2 基本变量示例

cangjie 复制代码
// variables.cj

// 全局变量
let globalConstant: String = "全局常量"
var globalVariable: String = "全局变量"

main() {
    // 局部变量
    let localConstant: Int64 = 42
    var localVariable: String = "局部变量"
    
    // 类型推断
    let inferredInt = 100
    let inferredString = "类型推断"
    let inferredFloat = 3.14
    
    // const 变量
    const PI = 3.14159265359
    const GRAVITY = 9.8
    
    println("全局常量: ${globalConstant}")
    println("全局变量: ${globalVariable}")
    println("局部常量: ${localConstant}")
    println("局部变量: ${localVariable}")
    println("推断整数: ${inferredInt}")
    println("推断字符串: ${inferredString}")
    println("推断浮点数: ${inferredFloat}")
    println("圆周率: ${PI}")
    println("重力加速度: ${GRAVITY}")
    
    // 修改变量值
    globalVariable = "修改后的全局变量"
    localVariable = "修改后的局部变量"
    
    println("修改后 - 全局变量: ${globalVariable}")
    println("修改后 - 局部变量: ${localVariable}")
}

4.3 延迟初始化示例

cangjie 复制代码
// delayed_initialization.cj

main() {
    // 延迟初始化 - 先声明后赋值
    let message: String
    let number: Int64
    
    // 在引用前必须初始化
    message = "Hello, Cangjie!"
    number = 42
    
    println("消息: ${message}")
    println("数字: ${number}")
    
    // 条件初始化
    let condition = true
    let conditionalValue: String
    
    if (condition) {
        conditionalValue = "条件为真"
    } else {
        conditionalValue = "条件为假"
    }
    
    println("条件值: ${conditionalValue}")
}

4.4 值类型和引用类型示例

cangjie 复制代码
// value_reference_types.cj

// 值类型 - struct
struct Point {
    Point(let x: Int64, let y: Int64) {}
}

// 引用类型 - class
class Person {
    var name: String
    var age: Int64

    public init(name: String, age: Int64) {
        this.name = name
        this.age = age
    }
}

main() {
    // 值类型示例
    let point1 = Point(10, 20)
    let point2 = point1 // 创建副本
    println("Point1: (${point1.x}, ${point1.y})")
    println("Point2: (${point2.x}, ${point2.y})")

    // 引用类型示例
    let person1 = Person("张三", 25)
    let person2 = person1 // 创建引用
    println("Person1: ${person1.name}, ${person1.age}")
    println("Person2: ${person2.name}, ${person2.age}")

    // 修改引用类型会影响所有引用
    person2.age = 30
    println("修改后 - Person1: ${person1.name}, ${person1.age}")
    println("修改后 - Person2: ${person2.name}, ${person2.age}")
}

5. 表达式(Expression)

5.1 代码块

仓颉中没有代码块,但是可以使用闭包代替

cangjie 复制代码
// code_blocks.cj
main() {
    let blockValue = {
        =>
            let a = 10
            let b = 20
            a + b
    }
    println("执行闭包,返回值: ${blockValue()}")
}

5.2 if 表达式

5.2.1 基本 if 表达式

cangjie 复制代码
// if_expressions.cj

main() {
    let number = 15
    
    // 基本 if-else
    if (number > 10) {
        println("数字大于10")
    } else {
        println("数字小于等于10")
    }
    
    // 多级 if-else
    if (number > 20) {
        println("数字大于20")
    } else if (number > 10) {
        println("数字大于10但小于等于20")
    } else {
        println("数字小于等于10")
    }
    
    // if 表达式作为值
    let result = if (number % 2 == 0) {
        "偶数"
    } else {
        "奇数"
    }
    println("${number} 是 ${result}")
    
    // 条件表达式
    let score = 85
    let grade = if (score >= 90) {
        "A"
    } else if (score >= 80) {
        "B"
    } else if (score >= 70) {
        "C"
    } else if (score >= 60) {
        "D"
    } else {
        "F"
    }
    println("分数 ${score} 对应等级: ${grade}")
}

5.2.2 涉及 let pattern 的 if 表达式

cangjie 复制代码
// let_pattern_if.cj

main() {
    // Option 类型示例
    let someValue = Some(42)
    let noneValue: Option<Int64> = None
    
    // 使用 let pattern 进行模式匹配
    if (let Some(value) <- someValue) {
        println("someValue 包含值: ${value}")
    } else {
        println("someValue 是 None")
    }
    
    if (let Some(value) <- noneValue) {
        println("noneValue 包含值: ${value}")
    } else {
        println("noneValue 是 None")
    }
    
    // 组合条件
    let anotherSome = Some(100)
    if (let Some(x) <- someValue && let Some(y) <- anotherSome) {
        println("两个值都存在: ${x} 和 ${y}")
    }
    
    // 逻辑或
    if (let Some(_) <- someValue || let Some(_) <- noneValue) {
        println("至少有一个是 Some")
    } else {
        println("都是 None")
    }
}

5.3 循环表达式

5.3.1 while 表达式

cangjie 复制代码
// while_expressions.cj

main() {
    // 基本 while 循环
    var counter = 0
    while (counter < 5) {
        println("计数器: ${counter}")
        counter++
    }
    
    // 计算阶乘
    var n = 5
    var factorial = 1
    while (n > 0) {
        factorial *= n
        n--
    }
    println("5! = ${factorial}")
    
    // 查找数组中的元素
    let numbers = [10, 20, 30, 40, 50]
    var index = 0
    var found = false
    
    while (index < numbers.size && !found) {
        if (numbers[index] == 30) {
            println("找到30,索引为: ${index}")
            found = true
        }
        index++
    }
    
    if (!found) {
        println("未找到30")
    }
}

5.3.2 do-while 表达式

cangjie 复制代码
// do_while_expressions.cj

main() {
    // 基本 do-while 循环
    var counter = 0
    do {
        println("do-while 计数器: ${counter}")
        counter++
    } while (counter < 3)
    
    // 至少执行一次的循环
    var number = 0
    do {
        println("当前数字: ${number}")
        number++
    } while (number <= 5)
    
    // 密码验证示例
    var attempts = 0
    let correctPassword = "cangjie123"
    var inputPassword = "wrong"
    
    do {
        attempts++
        println("尝试次数: ${attempts}")
        // 模拟密码验证
        if (attempts >= 3) {
            inputPassword = correctPassword
        }
    } while (inputPassword != correctPassword && attempts < 5)
    
    if (inputPassword == correctPassword) {
        println("密码验证成功!")
    } else {
        println("密码验证失败!")
    }
}

5.3.3 for-in 表达式

cangjie 复制代码
// for_in_expressions.cj

main() {
    // 遍历数组
    let fruits = ["苹果", "香蕉", "橙子", "葡萄"]
    println("水果列表:")
    for (fruit in fruits) {
        println("- ${fruit}")
    }
    
    // 遍历区间
    println("1到5的数字:")
    for (i in 1..=5) {
        println("数字: ${i}")
    }
    
    // 遍历区间(不包含结束值)
    println("0到4的数字:")
    for (i in 0..5) {
        println("数字: ${i}")
    }
    
    // 遍历元组数组
    let coordinates = [(1, 2), (3, 4), (5, 6)]
    println("坐标点:")
    for ((x, y) in coordinates) {
        println("(${x}, ${y})")
    }
    
    // 使用通配符
    var sum = 0
    for (_ in 0..5) {
        sum += 10
    }
    println("累加结果: ${sum}")
    
    // 使用 where 条件
    println("1到10中的偶数:")
    for (i in 1..=10 where i % 2 == 0) {
        println("偶数: ${i}")
    }
    
    // 嵌套循环
    println("乘法表 (1-3):")
    for (i in 1..=3) {
        for (j in 1..=3) {
            print("${i * j} ")
        }
        println()
    }
}

5.4 控制转移表达式

5.4.1 break 表达式

cangjie 复制代码
// break_expressions.cj

main() {
    // 在 for 循环中使用 break
    let numbers = [1, 3, 5, 7, 9, 2, 4, 6, 8, 10]
    
    println("查找第一个偶数:")
    for (number in numbers) {
        if (number % 2 == 0) {
            println("找到第一个偶数: ${number}")
            break
        }
    }
    
    // 在 while 循环中使用 break
    var counter = 0
    while (true) {
        counter++
        if (counter > 10) {
            break
        }
        if (counter % 2 == 0) {
            continue
        }
        println("奇数: ${counter}")
    }
    
    // 嵌套循环中的 break
    println("嵌套循环示例:")
    for (i in 1..=3) {
        for (j in 1..=3) {
            if (i == 2 && j == 2) {
                println("在 (2,2) 处跳出内层循环")
                break
            }
            println("(${i}, ${j})")
        }
    }
}

5.4.2 continue 表达式

cangjie 复制代码
// continue_expressions.cj
main() {
    // 在 for 循环中使用 continue
    println("打印1到10中的奇数:")
    for (i in 1..=10) {
        if (i % 2 == 0) {
            continue  // 跳过偶数
        }
        println("奇数: ${i}")
    }
    
    // 在 while 循环中使用 continue
    var number = 0
    println("打印小于10的3的倍数:")
    while (number < 10) {
        number++
        if (number % 3 != 0) {
            continue  // 跳过不是3的倍数的数
        }
        println("3的倍数: ${number}")
    }
    
    // 跳过特定值
    let scores = [85, 92, 78, 95, 88, 100, 76, 89]
    println("打印90分以上的成绩:")
    for (score in scores) {
        if (score < 90) {
            continue  // 跳过90分以下的成绩
        }
        println("优秀成绩: ${score}")
    }
    
    // 处理数组中的有效数据
    let data = [Some(1), Option<Int>.None, Some(3), Option<Int>.None, Some(5)]
    println("处理有效数据:")
    for (item in data) {
        if (let None <- item) {
            continue  // 跳过 None 值
        }
        if (let Some(value) <- item) {
            println("有效数据: ${value}")
        }
    }
}

6. 作用域(Scope)

6.1 作用域规则

仓颉语言中的作用域由大括号 {} 定义,遵循以下规则:

  1. 当前作用域中定义的程序元素在当前作用域和其内层作用域中有效
  2. 内层作用域中定义的程序元素在外层作用域中无效
  3. 内层作用域可以使用外层作用域中的名字重新定义绑定关系(变量遮蔽)

6.2 作用域示例

cangjie 复制代码
// scope_examples.cj
// 全局作用域
let globalVar: String = "全局变量"

func outerFunction() {
    let outerVar = "外层函数变量"
    println("外层函数: ${globalVar}")
    println("外层函数: ${outerVar}")

    func innerFunction() {
        let innerVar = "内层函数变量"
        println("内层函数: ${globalVar}")
        println("内层函数: ${outerVar}")
        println("内层函数: ${innerVar}")

        // 变量遮蔽
        let outerVar = "遮蔽的外层变量"
        println("内层函数(遮蔽后): ${outerVar}")
    }

    innerFunction()
    let globalVar: String = "遮蔽的全局变量"
    println("外层函数(遮蔽后): ${globalVar}")
}

main() {
    println("主函数: ${globalVar}")

    // 局部作用域
    do {
        let localVar = "局部作用域变量"
        println("局部作用域: ${localVar}")
        println("局部作用域: ${globalVar}")
    } while (false)

    // 条件作用域
    if (true) {
        let conditionalVar = "条件作用域变量"
        println("条件作用域: ${conditionalVar}")
    }

    // 循环作用域
    for (i in 1..=3) {
        let loopVar = "循环变量 ${i}"
        println("循环作用域: ${loopVar}")
    }

    outerFunction()
}

7. 综合示例

7.1 简单计算器

cangjie 复制代码
// calculator.cj
func add(a: Float64, b: Float64): Float64 {
    return a + b
}

func subtract(a: Float64, b: Float64): Float64 {
    return a - b
}

func multiply(a: Float64, b: Float64): Float64 {
    return a * b
}

func divide(a: Float64, b: Float64): Option<Float64> {
    if (b == 0.0) {
        return None
    } else {
        return Some(a / b)
    }
}

func calculate(operation: String, a: Float64, b: Float64): Option<Float64> {
    if (operation == "+") {
        return Some(add(a, b))
    } else if (operation == "-") {
        return Some(subtract(a, b))
    } else if (operation == "*") {
        return Some(multiply(a, b))
    } else if (operation == "/") {
        return divide(a, b)
    } else {
        return None
    }
}

main() {
    let operations = ["+", "-", "*", "/"]
    let numbers = [(10.0, 5.0), (15.0, 3.0), (8.0, 0.0)]
    
    println("简单计算器演示:")
    println("==================")
    
    for ((a, b) in numbers) {
        println("计算 ${a} 和 ${b}:")
        
        for (op in operations) {
            if (let Some(result) <- calculate(op, a, b)) {
                println("  ${a} ${op} ${b} = ${result}")
            } else {
                println("  ${a} ${op} ${b} = 错误(除零或无效操作)")
            }
        }
        println()
    }
}

7.2 学生成绩管理系统

cangjie 复制代码
// student_grade_system.cj
import std.collection.ArrayList

struct Student {
    let name: String
    let id: String
    var grades: ArrayList<Float64>
    
    public init(name: String, id: String) {
        this.name = name
        this.id = id
        this.grades = ArrayList<Float64>()
    }
    // 如果是public修饰的函数,必须显示标注返回值类型
    public func addGrade(grade: Float64): Unit {
        if (grade >= 0.0 && grade <= 100.0) {
            this.grades.add(grade)
        } else {
            println("无效成绩: ${grade}")
        }
    }
    
    public func getAverage(): Option<Float64> {
        if (this.grades.size == 0) {
            return None
        }
        
        var sum = 0.0
        for (grade in this.grades) {
            sum += grade
        }
        return Some(sum / Float64(this.grades.size))
    }
    
    public func getGradeLevel(): String {
        if (let Some(average) <- this.getAverage()) {
            if (average >= 90.0) {
                return "A"
            } else if (average >= 80.0) {
                return "B"
            } else if (average >= 70.0) {
                return "C"
            } else if (average >= 60.0) {
                return "D"
            } else {
                return "F"
            }
        } else {
            return "无成绩"
        }
    }
}

main() {
    // 创建学生
    let student1 = Student("张三", "2024001")
    let student2 = Student("李四", "2024002")
    let student3 = Student("王五", "2024003")
    
    // 添加成绩
    student1.addGrade(85.0)
    student1.addGrade(92.0)
    student1.addGrade(78.0)
    
    student2.addGrade(95.0)
    student2.addGrade(88.0)
    student2.addGrade(91.0)
    
    student3.addGrade(72.0)
    student3.addGrade(68.0)
    student3.addGrade(75.0)
    
    // 显示学生信息
    let students = [student1, student2, student3]
    
    println("学生成绩管理系统")
    println("==================")
    
    for (student in students) {
        println("学生: ${student.name} (ID: ${student.id})")
        
        if (let Some(average) <- student.getAverage()) {
            println("  平均分: ${average}")
            println("  等级: ${student.getGradeLevel()}")
        } else {
            println("  无成绩记录")
        }
        
        println("  成绩列表:")
        for (i in 0..student.grades.size) {
            println("    第${i + 1}次: ${student.grades[i]}")
        }
        println()
    }
    
    // 统计信息
    var totalStudents = 0
    var passedStudents = 0
    
    for (student in students) {
        totalStudents++
        if (let Some(average) <- student.getAverage()) {
            if (average >= 60.0) {
                passedStudents++
            }
        }
    }
    
    println("统计信息:")
    println("  总学生数: ${totalStudents}")
    println("  及格学生数: ${passedStudents}")
    println("  及格率: ${Float64(passedStudents) / Float64(totalStudents) * 100.0}%")
}
相关推荐
奶糖不太甜3 小时前
鸿蒙UI布局不兼容解决方案笔记
harmonyos
小小小小小星3 小时前
鸿蒙开发调试技巧整理
harmonyos
RAY_01046 小时前
2024鸿蒙样题需要掌握的知识点
华为·harmonyos
御承扬6 小时前
HarmonyOS NEXT系列之元服务框架ASCF
华为·harmonyos
HarderCoder7 小时前
重学仓颉-1从零开始学习现代编程语言
harmonyos
li理10 小时前
鸿蒙应用开发深度解析:从基础列表到瀑布流,全面掌握界面布局艺术
前端·前端框架·harmonyos
万少1 天前
可可图片编辑 HarmonyOS(2) 选择图片和保存到图库
harmonyos
小小小小小星1 天前
鸿蒙开发性能优化实战指南:从工具到代码全解析
性能优化·harmonyos
奶糖不太甜1 天前
鸿蒙元应用与服务卡片技术文档及案例
harmonyos