【华为鸿蒙开发技术】仓颉编程语言之函数调用语法糖指南

举报
柠檬味拥抱 发表于 2024/07/23 13:38:56 2024/07/23
【摘要】 仓颉编程语言仓颉编程语言是一种面向全场景应用开发的通用编程语言,兼顾开发效率和运行性能,提供了良好的编程体验。主要特点如下: 1. 语法简明高效提供简明高效的语法,如插值字符串、主构造函数、Flow 表达式、match、if-let、while-let、重导出等语法,减少冗余书写,提升开发效率。 2. 多范式编程支持函数式、命令式和面向对象等多范式编程,融合了高阶函数、代数数据类型、模式匹...

仓颉编程语言

仓颉编程语言是一种面向全场景应用开发的通用编程语言,兼顾开发效率和运行性能,提供了良好的编程体验。主要特点如下:

1. 语法简明高效

提供简明高效的语法,如插值字符串、主构造函数、Flow 表达式、match、if-let、while-let、重导出等语法,减少冗余书写,提升开发效率。

2. 多范式编程

支持函数式、命令式和面向对象等多范式编程,融合了高阶函数、代数数据类型、模式匹配、泛型等函数式语言的特性,以及封装、接口、继承、子类型多态等面向对象语言特性,还有值类型、全局函数等简洁高效的命令式语言特性。

3. 类型安全

静态强类型语言,通过编译时类型检查尽早识别程序错误,降低运行时风险,便于代码维护。强大的类型推断能力减少类型标注工作,提高开发效率。

4. 内存安全

支持自动内存管理,运行时进行数组下标越界检查、溢出检查等,确保运行时内存安全。

5. 高效并发

提供用户态轻量化线程(原生协程),以及简单易用的并发编程机制,保证并发场景的高效开发和运行。

6. 兼容语言生态

支持与 C 等主流编程语言的互操作,并采用便捷的声明式编程范式,实现对其他语言库的高效复用和生态兼容。

7. 领域易扩展

提供基于词法宏的元编程能力,支持在编译时变换代码,并提供尾随 lambda、属性、操作符重载、部分关键字可省略等特性,利于内嵌式领域专用语言(EDSL)的构建。

8. 助力 UI 开发

基于元编程和尾随 lambda 等特性,可以搭建声明式 UI 开发框架,提升 UI 开发效率和体验。

9. 内置库功能丰富

提供数据结构、常用算法、数学计算、正则匹配、系统交互、文件操作、网络通信、数据库访问、日志打印、解压缩、编解码、加解密和序列化等功能的内置库。

函数调用语法糖

尾随 lambda

函数最后一个形参是函数类型且调用时参数为 lambda 时,可以将 lambda 放在函数调用的尾部。仅一个 lambda 实参时,可以省略 ()

func myIf(a: Bool, fn: () -> Int64) {
    if(a) {
        fn()
    } else {
        0
    }
}

func test() {
    myIf(true, { => 100 }) // 普通调用

    myIf(true) {        // 尾随 lambda
        100
    }
}

Flow 表达式

包括 pipeline (|>) 和 composition (~>) 表达式,简化数据流处理和函数组合。

let res = arr |> inc |> sum // pipeline 表达式
var fg = f ~> g // composition 表达式

变长参数

形参最后一个非命名参数是 Array 类型时,实参可以直接传入参数序列代替 Array 字面量。

func sum(arr: Array<Int64>) {
    var total = 0
    for (x in arr) {
        total += x
    }
    return total
}

main() {
    println(sum())
    println(sum(1, 2, 3))
}

函数重载

同一作用域中,同名函数的参数不同(参数个数或参数类型不同)构成重载。

func f(a: Int64): Unit {}
func f(a: Float64): Unit {}
func f(a: Int64, b: Float64): Unit {}

泛型函数重命名泛型形参后,非泛型部分不同构成重载,否则重复定义错误。

interface I1{}
interface I2{}

func f1<X, Y>(a: X, b: Y) {}
func f1<Y, X>(a: X, b: Y) {} // 重载

类内构造函数参数不同构成重载,包括主构造函数和 init 构造函数。

class C {
    C(var a!: Int64, var b!: Float64) {
        this.a = a
        this.b = b
    }

    public init(a: Int64) {
        b = 0.0
        this.a = a
    }
}

不同作用域中定义的函数在共同可见的作用域中构成重载。

func f(a: Int64): Unit {}
func g() {
    func f(a: Float64): Unit {}
}

父类和子类中同名函数在共同可见的作用域中构成重载。

open class Base {
    public func f(a: Int64): Unit {}
}

class Sub <: Base {
    public func f(a: Float64): Unit {}
}

函数重载决议时,优先选择作用域级别高的函数和最匹配的函数。

open class Base {}
class Sub <: Base {}

func outer() {
    func g(a: Sub) {
        print("1")
    }
    func g(a: Base) {
        print("2")
    }

    g(Sub())   // 输出: 1
}

操作符重载

通过定义操作符函数为类型重载操作符,操作符函数需要在 func 关键字前添加 operator 修饰符。

一元和二元操作符重载

open class Point {
    var x: Int64 = 0
    var y: Int64 = 0
    public init (a: Int64, b: Int64) {
        x = a
        y = b
    }

    public operator func -(): Point {
        Point(-x, -y)
    }
    public operator func +(right: Point): Point {
        Point(this.x + right.x, this.y + right.y)
    }
}

索引操作符重载

class A {
    operator func [](arg1: Int64, arg2: String): Int64 {
        return 0
    }

    operator func [](arg1: Int64, arg2: String, value!: Int64): Unit {
        return
    }
}

函数调用操作符重载

open class A {
    public init() {}

    public operator func ()(): Unit {}
}

func test1() {
    let a = A()
    a()
}

操作符重载的优先级和结合性不变。可以被重载的操作符包括 (), [], !, -, **, *, /, %, +, -, <<, >>, <, <= 等。

可重载的运算符

运算符 描述
> 大于
>= 大于或等于
== 等于
!= 不等于
& 按位与
^ 按位异或
| 按位或
&& 逻辑与
|| 逻辑或
范围
-> Lambda 定义
= 赋值
+= 加等于
-= 减等于
*= 乘等于
/= 除等于
%= 取余等于
<<= 左移等于
>>= 右移等于
&= 按位与等于
^= 按位异或等于
|= 按位或等于

扩展(Extend)

如果需要为现有类型添加新的方法,可以使用 extend 关键字定义扩展。

扩展的定义和使用

  • 可以使用 extend 关键字为现有的类、接口、结构体和枚举类型添加新方法。
  • 扩展不能添加存储属性,但可以添加计算属性。
  • 扩展可以为现有类型添加新的构造函数、方法和计算属性,但不能重写已有的方法或属性。

示例

以下示例展示了如何使用扩展为现有类型添加新的方法和计算属性:

// 为 Int 类型添加一个计算属性和一个方法
extend Int {
    // 添加计算属性 isEven,判断数字是否为偶数
    var isEven: Bool {
        get {
            self % 2 == 0
        }
    }
    
    // 添加方法 square,返回数字的平方
    func square(): Int {
        self * self
    }
}

func main() {
    let x = 4
    println(x.isEven) // 输出:true
    println(x.square()) // 输出:16
}

使用限制

  • 扩展不能重写现有类型的方法或属性。
  • 扩展不能添加存储属性。
  • 扩展可以为现有类型添加新的构造函数、方法和计算属性。

扩展的应用场景

  • 为现有类型添加新的方法和属性,而不需要继承或修改现有类型的源码。
  • 扩展标准库类型或第三方库类型,以便在不改变原有代码的情况下增强其功能。
  • 在保持代码简洁和模块化的同时,增加类型的功能和行为。

模式匹配(Pattern Matching)

模式匹配是一种强大的语法特性,用于检查数据结构并从中提取值。仓颉编程语言支持多种模式匹配形式,包括值匹配、元组匹配、数组匹配、对象匹配和枚举匹配等。

示例

以下是一些模式匹配的示例:

值匹配

func describe(x: Int) {
    match (x) {
        case 0 => println("Zero")
        case 1 => println("One")
        case _ => println("Other")
    }
}

func main() {
    describe(0) // 输出:Zero
    describe(1) // 输出:One
    describe(2) // 输出:Other
}

元组匹配

func describe(point: (Int, Int)) {
    match (point) {
        case (0, 0) => println("Origin")
        case (x, 0) => println("On the X-axis")
        case (0, y) => println("On the Y-axis")
        case _ => println("Somewhere else")
    }
}

func main() {
    describe((0, 0)) // 输出:Origin
    describe((1, 0)) // 输出:On the X-axis
    describe((0, 1)) // 输出:On the Y-axis
    describe((1, 1)) // 输出:Somewhere else
}

数组匹配

func describe(arr: Array<Int>) {
    match (arr) {
        case [1, 2, 3] => println("1, 2, 3")
        case [1, 2, _] => println("1, 2, something else")
        case _ => println("Other")
    }
}

func main() {
    describe([1, 2, 3]) // 输出:1, 2, 3
    describe([1, 2, 4]) // 输出:1, 2, something else
    describe([2, 3, 4]) // 输出:Other
}

对象匹配

class Point(var x: Int, var y: Int)

func describe(p: Point) {
    match (p) {
        case Point(0, 0) => println("Origin")
        case Point(x, 0) => println("On the X-axis")
        case Point(0, y) => println("On the Y-axis")
        case _ => println("Somewhere else")
    }
}

func main() {
    let p1 = Point(0, 0)
    let p2 = Point(1, 0)
    let p3 = Point(0, 1)
    let p4 = Point(1, 1)
    
    describe(p1) // 输出:Origin
    describe(p2) // 输出:On the X-axis
    describe(p3) // 输出:On the Y-axis
    describe(p4) // 输出:Somewhere else
}

枚举匹配

enum Shape {
    case Circle(radius: Float)
    case Rectangle(width: Float, height: Float)
}

func describe(s: Shape) {
    match (s) {
        case Circle(radius) => println("Circle with radius \(radius)")
        case Rectangle(width, height) => println("Rectangle with width \(width) and height \(height)")
    }
}

func main() {
    let circle = Circle(5.0)
    let rectangle = Rectangle(10.0, 20.0)
    
    describe(circle) // 输出:Circle with radius 5.0
    describe(rectangle) // 输出:Rectangle with width 10.0 and height 20.0
}

注意事项

  • 模式匹配中的变量绑定可以在匹配成功后直接使用。
  • match 语句可以像 switch 语句一样,处理多种情况,并提供默认情况。

通过模式匹配,可以以一种简洁和直观的方式检查和解构复杂的数据结构,从而使代码更加清晰和易于维护。

总结

仓颉编程语言以其简洁的语法和强大的功能,适用于各种编程任务。通过面向对象的设计、扩展机制和模式匹配,提供了灵活且易于维护的编程方式。适合初学者和有经验的开发者。

image.png

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。