文章目录
- ⭐前言
- 🔠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 = 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