(仓颉) 仓颉语言入门

2024-09-07 16:44
文章标签 语言 入门 仓颉

本文主要是介绍(仓颉) 仓颉语言入门,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • ⭐前言
  • 🔠1 基本概念
    • 🔤Hello World
    • 🔤标识符
    • 🔤内置类型
    • 🔤if表达式
    • 🔤for表达式
    • 🔤while表达式
    • 🔤demo 手动计算Π
  • 🔠2 函数
    • 🔤普通函数
    • 🔤lambda
    • 🔤demo 递归遍历目录
  • 🔠3 枚举
    • 🔤enum
    • 🔤match表达式
    • 🔤option 解析数字
    • 🔤demo 计算表达式
  • 🔠4 struct
    • 🔤值类型
    • 🔤二叉树
  • 🔠5 calss
    • 🔤引用类型
    • 🔤继承
    • 🔤prop 属性
  • 🔠6 接口与扩展
    • 🔤interface
    • 🔤extend
    • 🔤泛型
  • 🔠7 异常处理
    • 🔤try catch finally
  • 🔠8 并发编程
    • 🔤Future
  • 🔠9 跨语言互操作
  • 🔠10 宏
    • 🔤macro
  • ⭐END
    • 🌟交流方式

⭐前言

仓颉-鸿蒙原生应用编程语言-华为开发者联盟 (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 = 10let ___x = "___Str"println(num)println(___x)// 原始表示符// 用于将关键字作为标识符let `for` = "这是一个将for关键字用作原始标识符"println(`for`)
}

🔤内置类型

main() {/*** 字面量后缀* 整形* Int8  -> i8* Uint8 -> u8* 浮点型* Float16 -> f16*/let a: Int64 = 2024let b = 67u8let c: Float64 = 6.21let d: Bool = true || falseprintln(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.0println("${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. forvar sum = 0// range(1, 100, 2)for (i in 1..99 : 2) {sum += i}println(sum)// 2. forlet arr = [(1, 2), (3, 4)]// 元组可以解构for ((x, y) in arr) {println("x=${x} y=${y}")}// 3. forvar 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.0var lower = 1.0var upper = 2.0while (upper - lower > 1.0E-10) {result = (lower + upper) / 2.0if (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 = 10000var n: UInt32 = 0let 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.0println("Π = ${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 = x0for (_ in 0..n) {print("${x}, ")x = f(x)}println("${x}")
}main() {// lambda 表达式// { 参数列表 => 函数体 }// { params => block }// 周期3iter(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 => ncase 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 = 0for (i in sign..text.size) {if (text[i] > 57u8 || text[i] < 48u8) {return None}let digit = Int64(text[i] - 48u8)sum = 10 * sum + digit}// 自动包装为 optionreturn 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) => numbercase 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 = xthis.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 = xthis.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 = 0public 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 = numberupdate()left?.param = number / 2right?.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): Float64operator func <<(that: Slot): Slot {return this}operator func >>(that: Slot): Slot {that << thisreturn 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 = Nonevar sum = 0.0public 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.001let 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.sizelet offset = size - n % sizethis[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 = 0for (i in sign..text.size) {if (text[i] > 57u8 || text[i] < 48u8) {throw ParseException()}let digit = Int64(text[i] - 48u8)sum = 10 * sum + digit}// 自动包装为 optionreturn 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 = 16func task(): Int64 {var n: Int64 = 0let 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 = 0for (future in futures) {n += future.get()}let pi = Float64(n) / Float64(M * N) * 4.0println("Π = ${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

这篇关于(仓颉) 仓颉语言入门的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1145589

相关文章

深入理解Go语言中二维切片的使用

《深入理解Go语言中二维切片的使用》本文深入讲解了Go语言中二维切片的概念与应用,用于表示矩阵、表格等二维数据结构,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来一起学习学习吧... 目录引言二维切片的基本概念定义创建二维切片二维切片的操作访问元素修改元素遍历二维切片二维切片的动态调整追加行动态

Go语言中make和new的区别及说明

《Go语言中make和new的区别及说明》:本文主要介绍Go语言中make和new的区别及说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1 概述2 new 函数2.1 功能2.2 语法2.3 初始化案例3 make 函数3.1 功能3.2 语法3.3 初始化

从入门到精通MySQL联合查询

《从入门到精通MySQL联合查询》:本文主要介绍从入门到精通MySQL联合查询,本文通过实例代码给大家介绍的非常详细,需要的朋友可以参考下... 目录摘要1. 多表联合查询时mysql内部原理2. 内连接3. 外连接4. 自连接5. 子查询6. 合并查询7. 插入查询结果摘要前面我们学习了数据库设计时要满

从入门到精通C++11 <chrono> 库特性

《从入门到精通C++11<chrono>库特性》chrono库是C++11中一个非常强大和实用的库,它为时间处理提供了丰富的功能和类型安全的接口,通过本文的介绍,我们了解了chrono库的基本概念... 目录一、引言1.1 为什么需要<chrono>库1.2<chrono>库的基本概念二、时间段(Durat

Go语言中nil判断的注意事项(最新推荐)

《Go语言中nil判断的注意事项(最新推荐)》本文给大家介绍Go语言中nil判断的注意事项,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录1.接口变量的特殊行为2.nil的合法类型3.nil值的实用行为4.自定义类型与nil5.反射判断nil6.函数返回的

Go语言数据库编程GORM 的基本使用详解

《Go语言数据库编程GORM的基本使用详解》GORM是Go语言流行的ORM框架,封装database/sql,支持自动迁移、关联、事务等,提供CRUD、条件查询、钩子函数、日志等功能,简化数据库操作... 目录一、安装与初始化1. 安装 GORM 及数据库驱动2. 建立数据库连接二、定义模型结构体三、自动迁

解析C++11 static_assert及与Boost库的关联从入门到精通

《解析C++11static_assert及与Boost库的关联从入门到精通》static_assert是C++中强大的编译时验证工具,它能够在编译阶段拦截不符合预期的类型或值,增强代码的健壮性,通... 目录一、背景知识:传统断言方法的局限性1.1 assert宏1.2 #error指令1.3 第三方解决

Go语言代码格式化的技巧分享

《Go语言代码格式化的技巧分享》在Go语言的开发过程中,代码格式化是一个看似细微却至关重要的环节,良好的代码格式化不仅能提升代码的可读性,还能促进团队协作,减少因代码风格差异引发的问题,Go在代码格式... 目录一、Go 语言代码格式化的重要性二、Go 语言代码格式化工具:gofmt 与 go fmt(一)

从入门到精通MySQL 数据库索引(实战案例)

《从入门到精通MySQL数据库索引(实战案例)》索引是数据库的目录,提升查询速度,主要类型包括BTree、Hash、全文、空间索引,需根据场景选择,建议用于高频查询、关联字段、排序等,避免重复率高或... 目录一、索引是什么?能干嘛?核心作用:二、索引的 4 种主要类型(附通俗例子)1. BTree 索引(

Redis 配置文件使用建议redis.conf 从入门到实战

《Redis配置文件使用建议redis.conf从入门到实战》Redis配置方式包括配置文件、命令行参数、运行时CONFIG命令,支持动态修改参数及持久化,常用项涉及端口、绑定、内存策略等,版本8... 目录一、Redis.conf 是什么?二、命令行方式传参(适用于测试)三、运行时动态修改配置(不重启服务