(仓颉) 仓颉语言入门

⭐前言

仓颉-鸿蒙原生应用编程语言-华为开发者联盟 (huawei.com)

初识仓颉语言-仓颉编程语言开发指南-学习仓颉语言 - 华为HarmonyOS开发者 (huawei.com)

【原创】仓颉编程语言入门教程

楼主作为主语言C++,副语言python。仅做基础的入门了解。

本文不做任何格外的语法说明,仅在代码中用简短的注释辅助。

下文均为教学视频中的实例demo(上方的视频也出现在官网的视频一栏中)。

本文所有代码均在下方的在线编译器中进行尝试。

除了最后两章,9,10无法进行单文件操作其余均有验证。

仓颉 Playground (zxilly.dev)

https://github.com/Zxilly/playground-cj

仓颉版本 0.54.3

package cangjie

// 编写你的第一个仓颉程序
main(): Int64 {
    println("你好,仓颉!")
    return 0
}

🔠1 基本概念

🔤Hello World

// main 可以没有返回值
main() {
    println("你好,仓颉!")
}

🔤标识符

main() {
    // 普通变量
    let num = 10
    let ___x = "___Str"

    println(num)
    println(___x)

    // 原始表示符
    // 用于将关键字作为标识符
    let `for` = "这是一个将for关键字用作原始标识符"
    println(`for`)
}

🔤内置类型

main() {
    /**
     * 字面量后缀
     * 整形
     * Int8  -> i8
     * Uint8 -> u8
     * 浮点型
     * Float16 -> f16
     */
    let a: Int64 = 2024
    let b = 67u8
    let c: Float64 = 6.21

    let d: Bool = true || false
    println(d)

    // 字符类型,表示一个 unicode 字符
    // 运行下来双引号也可以运行
    let e: Rune = '仓'
    let f: Rune = '\u{9889}'
    println("${e} ${f}")

    // 单行字符串
    let g: String = "Cang" + "jie"
    let h: String = """
        第1行,这是多行字符串
        第2行
"""
    // 插值字符串
    // 要求表达式类型实现了 ToString 接口
    let i: String = "Cangjie${a}"
    println("${h}${i}")

    // 引用类型数组
    let j: Array<UInt8> = [1u8, 2u8]
    // 值类型数组
    // 没有 ToString
    // let k: VArray<Rune, $2> = ['C', 'J']
    let k: VArray<Rune, $2> = [e, f]
    println("引用类型数组${j}")

    // 元组类型
    let l: (Int64, Float64) = (2024, 9.6)
    // expected 'Struct-String', found 'Tuple<Int64, Float64>'
    // println(l)

    // 区间类型
    // 主要用于for in表达式中
    let m: Range<Int64> = 2019..2024
    // expected 'Struct-String', found 'Struct-Range<Int64>'
    // println(m)
}

🔤if表达式

import std.random.*

main() {
    let speed = Random().nextFloat64() + 20.0
    println("${speed} km/s")

    // if 表达式
    // 类似于 gcc 中的大括号表达式
    let level = if (speed > 16.7) {
        "第3宇宙速度"
    } else if (speed > 11.2) {
        "第2宇宙速度"
    } else if (speed > 7.9) {
        "第1宇宙速度"
    } else {
        "第0宇宙速度"
    }

    println(level)
}

🔤for表达式

main() {
    // 1. for
    var sum = 0
    // range(1, 100, 2)
    for (i in 1..99 : 2) {
        sum += i
    }
    println(sum)

    // 2. for
    let arr = [(1, 2), (3, 4)]
    // 元组可以解构
    for ((x, y) in arr) {
        println("x=${x} y=${y}")
    }

    // 3. for
    var num = 2
    // 用 _ 作为占用,避免编译器警告
    for (_ in 0..5) {
        num *= num
    }

    // 4. for
    // 当 where 为 true 才执行循环体
    for (i in 0..10 where i % 2 == 1) {
        println(i)
    }
}

🔤while表达式

main() {
    var result = 0.0
    var lower = 1.0
    var upper = 2.0

    while (upper - lower > 1.0E-10) {
        result = (lower + upper) / 2.0
        if (result ** 2 - 2.0 > 0.0) {
            upper = result
        } else {
            lower = result
        }
    }

    println("√2 ≈ ${result}")
}

🔤demo 手动计算Π

// 在在线仓颉Playground 中运行失败
// from std import random.*
// from std import math.*
import std.random.*
import std.math.*

main() {
    /**
     * 手动计算圆周率
     * 在一个正方形中随机投点
     */
    const N = 10000
    var n: UInt32 = 0
    let random = Random()
    for (_ in 0..N) {
        let x = random.nextFloat64()
        let y = random.nextFloat64()
        if ((x - 0.5) ** 2 + (y - 0.5) ** 2 < 0.25) {
            n++
        }
    }

    let pi = Float64(n) / Float64(N) * 4.0
    println("Π = ${pi}")
    println("deviation: ${abs(Float64.PI - pi)}")
}

🔠2 函数

🔤普通函数

func void() {
    // pass
}

// 将函数作为参数
func node(value: Int32, left!: () -> Unit = void, right!: () -> Unit = void) {
    // 二叉树的中序遍历
    func show() {
        left()
        print(value)
        right()
    }

    return show
}

main() {
    let tree = node(
        0,
        left: node(1, left: node(2, right: node(3))),
        right: node(4, left: node(5), right: node(6))
    )
    tree()
}

🔤lambda

func iter(n: Int64, x0: Float64, f: (Float64) -> Float64) {
    var x = x0
    for (_ in 0..n) {
        print("${x}, ")
        x = f(x)
    }
    println("${x}")
}

main() {
    // lambda 表达式
    // { 参数列表 => 函数体 }
    // { params => block }

    // 周期3
    iter(5, 0.8, {x: Float64 => 1.0 / (1.0 - x)})
    // 没有周期,产生未随机数
    iter(10, 0.8, {x: Float64 => 4.0 * x * (1.0 - x)})
}

🔤demo 递归遍历目录

import std.fs.*

func forEachFileDo(root: Path, handler: (Path) -> Unit): Unit {
    let current = Directory(root)
    for (file in current.files()) {
        handler(file.path)
    }
    for (directory in current.directories()) {
        forEachFileDo(directory.path, handler)
    }
}

main() {
    forEachFileDo(Path("."), {path: Path => println(path)})
}

🔠3 枚举

🔤enum

enum Tree {
    // 枚举项
    Empty | Leaf(Int64) | Node(Int64, Tree, Tree)

    // 成员函数
    public func traverse(): Unit {
        match (this) {
            case Empty => ()
            case Leaf(value) => print(value)
            case Node(value, left, right) =>
                left.traverse()
                print(value)
                right.traverse()
        }
    }

    public static func generate(depth: UInt8): Tree {
        if (depth == 1) {
            return Leaf(1)
        }
        return Node(
            Int64(depth),
            generate(depth - 1),
            generate(depth - 1)
        )
    }
}

main() {
    let tree = Node(
        1,
        Node(2, Node(3, Empty, Leaf(4)), Empty),
        Node(5, Leaf(6), Leaf(7))
    )
    tree.traverse()
    println()
    let fullTree = Tree.generate(5)
    fullTree.traverse()
}

🔤match表达式

func fib(n: Int64): Int64 {
    // math 表达式
    match (n) {
        case 0 | 1 => n
        case other where other > 0 => fib(other - 1) + fib(other - 2)
        case _ => 0
    }
}

main() {
    println(fib(-1))
    for (i in 1..=10) {
        print("${fib(i)} ")
    }
}

🔤option 解析数字

func parseInt(text: String): Option<Int64> {
    if (text.isEmpty() || text == ".") {
        return None
    }
    var sign = if (text[0] == 45u8) {
        1
    } else {
        0
    }
    var sum = 0
    for (i in sign..text.size) {
        if (text[i] > 57u8 || text[i] < 48u8) {
            return None
        }
        let digit = Int64(text[i] - 48u8)
        sum = 10 * sum + digit
    }

    // 自动包装为 option
    return if (sign == 1) {
        -sum
    } else {
        sum
    }
}

main() {
    let number = parseInt("-123456")
    // getOrThrow 从 Option 取值
    println(number.getOrThrow())

    let result = parseInt("123-456")
    if (result.isNone()) {
        println("parse failed")
    }
}

🔤demo 计算表达式

enum Expr {
    Num(Float64)
    | Add(Expr, Expr)
    | Sub(Expr, Expr)
    | Mul(Expr, Expr)
    | Div(Expr, Expr)

    public func calc(): Float64 {
        match (this) {
            case Num(number) => number
            case Add(a, b) => a.calc() + b.calc()
            case Sub(a, b) => a.calc() - b.calc()
            case Mul(a, b) => a.calc() * b.calc()
            case Div(a, b) => a.calc() / b.calc()
        }
    }

    public operator func +(that: Expr): Expr {
        return Add(this, that)
    }
    public operator func -(that: Expr): Expr {
        return Sub(this, that)
    }
    public operator func *(that: Expr): Expr {
        return Mul(this, that)
    }
    public operator func /(that: Expr): Expr {
        return Div(this, that)
    }
}

main() {
    let x = Num(1.2) + Num(3.4) + Num(2.0) - Num(1.0) / Num(2.0)
    println(x.calc())
}

🔠4 struct

🔤值类型

struct Point {
    static let name = "Point"

    // 主构造函数
    // 自动成为成员变量
    Point(private var x: Float64, private var y: Float64) {
        println("Create a point: (${x}, ${y})")
    }

    public func copy() {
        return this
    }

    // 用 mut 修饰可以使用 this 引用当前实例
    public mut func set(x: Float64, y: Float64) {
        this.x = x
        this.y = y
    }

    public func show() {
        println("Visit the point: (${x}, ${y})")
    }
}

main() {
    println(Point.name)
    let p1 = Point(3.0, 4.0)
    var p2 = p1.copy()
    p2.set(1.0, 2.0)
    p1.show()
    p2.show()
}

🔤二叉树

struct Node {
    public Node(var value: Int32, let left!: ?Node = None, let right!: ?Node = None) {
    }

    public func traverse(): Unit {
        // Option 类型的语法糖
        left?.traverse()
        print(value)
        right?.traverse()
    }

    static let name: String
    // 静态构造函数
    static init() {
        name = "Binary Tree"
    }

    public static func intro() {
        println(name)
    }
}

main() {
    Node.intro()
    let root = Node(
        1,
        left: Node(2, left: Node(3, right: Node(4))),
        right: Node(5, left: Node(6), right: Node(7))
    )
    root.traverse()
}

🔠5 calss

🔤引用类型

class Point {
    static let name = "Point"
    public Point(private var x: Float64, private var y: Float64) {
        println("Create a point: {${x}, ${y}}")
    }

    // this 是当前的引用
    public func ref() {
        return this
    }

    public func set(x: Float64, y: Float64) {
        this.x = x
        this.y = y
    }

    public func show() {
        println("Visit the point: (${x}, ${y})")
    }
}

main() {
    println(Point.name)
    let p1 = Point(3.0, 4.0)
    var p2 = p1.ref()
    p2.set(1.0, 2.0)
    p1.show()
    p2.show()
}

🔤继承

// 使用了 open 关键字的才能被继承
open class NodeA {
    public NodeA(
        protected var value: String,
        protected let left!: ?NodeA = None,
        protected let right!: ?NodeA = None
    ) {
    }

    // 中序遍历
    public open func traverse(): Unit {
        left?.traverse()
        print(value)
        right?.traverse()
    }
}

class NodeB <: NodeA {
    public init(
        value: String,
        left!: ?NodeA = None,
        right!: ?NodeA = None
    ) {
        super(value, left: left, right: right)
    }

    // 前序遍历
    public func traverse(): Unit {
        print(value)
        left?.traverse()
        right?.traverse()
    }
}

main() {
    let root = NodeA(
        'a',
        left: NodeA('b', left: NodeA('c', right: NodeA('d'))),
        right: NodeB('e', left: NodeB('f'), right: NodeB('g'))
    )
    root.traverse()
}

🔤prop 属性

class Node {
    private var value: Int64 = 0
    public Node(
        private var name: String,
        private let left!: ?Node = None,
        private let right!: ?Node = None
    ) {
    }

    // 是 class 不是 struct
    // 属性,mut 中才能定义set
    // 此处属性名:param
    // 这里的目的是和成员变量 value 进行关联
    public mut prop param: Int64 {
        get() {
            value
        }
        set(number) {
            value = number
            update()
            left?.param = number / 2
            right?.param = number / 2
        }
    }

    private func update() {
        println("${name} has been updated to ${value}")
    }
}

main() {
    var root = Node(
        'a',
        left: Node('b', left: Node('c', right: Node('d'))),
        right: Node('e', left: Node('f'), right: Node('g'))
    )
    println(root.param)
    root.param = 128
}

🔠6 接口与扩展

🔤interface

import std.math.*

interface Slot {
    func compute(t: Float64): Float64
    operator func <<(that: Slot): Slot {
        return this
    }
    operator func >>(that: Slot): Slot {
        that << this
        return this
    }
}

extend Float64 <: Slot {
    public func compute(t: Float64): Float64 {
        return this
    }
}

class Wave <: Slot {
    public Wave(let freq: Float64, let phi: Float64) {}
    public func compute(t: Float64): Float64 {
        return sin(2.0 * Float64.PI * freq * t + phi)
    }
}

class Mut <: Slot {
    public Mut(let a: Slot, let b: Slot) {}
    public func compute(t: Float64): Float64 {
        a.compute(t) * b.compute(t)
    }
}

class Integrator <: Slot {
    var input: ?Slot = None
    var sum = 0.0
    public Integrator(let dt: Float64) {}
    public func compute(t: Float64): Float64 {
        sum += dt * input.getOrThrow().compute(t)
        return sum
    }
    public operator func <<(that: Slot): Slot {
        input = Some(that)
        this
    }
}

main() {
    const DT = 0.001
    let left = 1.0 >> Integrator(DT)
    let right = Wave(0.5 / Float64.PI, 0.0)
    let flow = Mut(left, right) >> Integrator(DT)
    for (t in 0..1000) {
        println(flow.compute(Float64(t) * DT))
    }
}

🔤extend

// 默认情况下,扩展仅在当前包中有效
extend String {
    operator func >>(n: Int64): String {
        if (n <= 0) {
            return this.clone()
        }
        let size = this.size
        let offset = size - n % size
        this[offset..size] + this[0..offset]
    }
}

main() {
    let text = "Cangjie2024"
    println(text >> 2 >> 2)
}

🔤泛型

class Node<T> where T <: ToString {
    public Node(
        protected var value: T,
        protected let left!: ?Node<T> = None,
        protected let right!: ?Node<T> = None
    ) {
    }

    // 中序遍历
    public func traverse(): Unit {
        left?.traverse()
        print(value)
        right?.traverse()
    }
}

main() {
    let tree1 = Node(
        'a',
        left: Node('b', left: Node('c', right: Node('d'))),
        right: Node('e', left: Node('f'), right: Node('g'))
    )
    tree1.traverse()

    println()

    let tree2 = Node(
        1,
        left: Node(2, left: Node(3, right: Node(4))),
        right: Node(5, left: Node(6), right: Node(7))
    )
    tree2.traverse()
}

🔠7 异常处理

🔤try catch finally

class ParseException <: Exception {
    public init() {
        super("Parse Failed")
    }
}

func parseInt(text: String): Int64 {
    if (text.isEmpty() || text == ".") {
        throw ParseException()
    }
    var sign = if (text[0] == 45u8) {
        1
    } else {
        0
    }
    var sum = 0
    for (i in sign..text.size) {
        if (text[i] > 57u8 || text[i] < 48u8) {
            throw ParseException()
        }
        let digit = Int64(text[i] - 48u8)
        sum = 10 * sum + digit
    }

    // 自动包装为 option
    return if (sign == 1) {
        -sum
    } else {
        sum
    }
}

main() {
    println(parseInt("-123456"))
    let number = try {
        parseInt("123-456")
    } catch (e: ParseException) {
        println("not an integer")
        0
    }
    println(number)

    try {
        parseInt("123x456")
        println(parseInt("-123456"))
    } catch (e: ParseException) {
        println(e.message)
    } finally {
        println("clean up")
    }

    // parseInt("x123456")
    println("end")
}

🔠8 并发编程

🔤Future

import std.collection.*
import std.random.*
import std.math.*

const M = 200000
const N = 16

func task(): Int64 {
    var n: Int64 = 0
    let random = Random()
    for (_ in 0..M) {
        let x = random.nextFloat64()
        let y = random.nextFloat64()
        if ((x - 0.5) ** 2 + (y - 0.5) ** 2 < 0.25) {
            n++
        }
    }
    return n
}

main() {
    let futures = ArrayList<Future<Int64>>()
    for (_ in 0..N) {
        let future = spawn {task()}
        futures.append(future)
    }

    var n = 0
    for (future in futures) {
        n += future.get()
    }

    let pi = Float64(n) / Float64(M * N) * 4.0
    println("Π = ${pi}")
    println("deviation: ${abs(Float64.PI - pi)}")
}

🔠9 跨语言互操作

🔠10 宏

🔤macro

// macro.cj
// 宏需要定义在宏包
macro package meta
import std.ast.*

public macro transform(tokens: Tokens): Tokens {
    for (token in tokens) {
        println("${token.value}\t\t${token.kind}")
    }
    println("--------------")
    return tokens
}

// main.cj
import meta.*

@transform
func add(x: Int64, y: Int64) {
    return x + y
}

main() {
    @transform(add(1, 2))
}



⭐END

🌟交流方式

⭐交流方式⭐ |C/C++|算法|设计模式|软件架构-CSDN社区

关注我,学习更多C/C++,python,算法,软件工程,计算机知识

B站:

👨‍💻主页:天赐细莲 bilibili

  • 8
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值