# 1.3:仓颉语言简介

仓颉编程语言是华为研发的一种面向全场景应用开发的现代编程语言,具有高效编程、安全可靠、轻松并发和卓越性能等特点。本节笔者简单介绍一下仓颉语言的部分语法和使用。

# 1.3.1:数据类型

  1. 整数

    仓颉把整数分为有符号和无符号两种类型,有符号整数用 Int8Int16Int32Int64IntNative 来表示,无符号整数用 UInt8UInt16UInt32UInt64UIntNative 来表示。

    var count1: Int8 = 6             // 声明count1为Int8类型
    var count2: Int64 = 6            // 声明count2为Int64类型
    var count3 = 6                   // count3无指定类型时默认推导为Int64类型
    if (count3 is Int64) {
        println("count3是Int64类型"); // 输出count3是Int64类型
    }
    
    1
    2
    3
    4
    5
    6

    📢:具体使用哪种类型取决于该程序中需要处理的整数的性质和范围。在 Int64 类型适合的情况下,首选 Int64 类型,具体范围可参见官网 (opens new window)

  2. 小数

    仓颉提供了 Float16Float32Float64 分别表示编码长度为 16-bit32-bit64-bit 的小数。

    var count1: Float32 = 3.14     // 声明count1为Float32类型
    var count2: Float64 = 3.14     // 声明count2为Float64类型
    var count3 = 3.14              // 声明count3为默认类型
    
    if (count3 is Float64) {
        println("默认是Float64类型");// 输出默认是Float64类型
    }
    if (count3 == count2) {
        println("count3 == count2") // 输出count3 == count2
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10

    📢:在多种浮点类型都适合的情况下,首选精度高的浮点类型Float64。具体范围可参见官网 (opens new window)

  3. Bool

    仓颉提供了 Bool 关键字来表示逻辑值 truefalse

    let a: Bool = true
    let b: Bool = false
    
    1
    2
  4. Rune

    仓颉提供了 Rune 关键字来表示字符,格式为:r"*" 或者 r'*' 的形式。

    var char1: Rune = r'a'
    var char2 = r"a"
    
    if(char1 is Rune) {
        println("char1 is Rune")   // 输出char1 is Rune
    } else {
        println("char1 isn't Rune")
    }
    if (char1 == char2) {
        println("char1 == char2")  // 输出char1 == char2
    } else {
        println("char1 != char2")
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
  5. String

    仓颉提供了 String 关键字来表示字符串类型,使用单引号(')或双引号(")来表示字符串类型,同时支持插值字符串的表达形式,如 "${a + b}"。

    let fruit = "apples"
    let count = 10
    let s = "There are ${count * count} ${fruit}"
    
    1
    2
    3
  6. Array

    仓颉使用 Array 关键字来表示单一类型的有序数组。

    var array1: Array<String> = ["1", "2", "3"]
    var array2 = [1, 2, 3]
    
    println(array1[2])
    
    for (e in array2) {
      println("the element is ${e}")
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
  7. 元组

    仓颉提供了元组来表示已知元素数量和类型的数组,元组内的各元素的类型不必相同,但是对应位置的类型必须一致。

    var tuple1: (Bool, Float64, String) = (false, 3.14, "cj") // 定义元组tuple1并制定类型
    var tuple2 = (123, true, 3.14)                            // 定义元组tuple2由编译器推导类型
    println(tuple1[0])                                        // 访问元组,输出false
    println(tuple2[2])                                        // 访问元组,输出3.140000
    
    1
    2
    3
    4
  8. Unit

    Unit 是一种特殊的数据类型,适用于只关心副作用而不关心值的表达式,例如,print 函数、赋值表达式、复合赋值表达式、自增和自减表达式、循环表达式,它们的类型都是 Unit

    main(): Int64 {
        
        println("unit")
        testUnit()
        
        return 0
    }
    
    func testUnit(): Unit {
        var age = 20
        age++
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
  9. Any

    仓颉提供了 Any 接口,它是一个空实现,所有数据均实现了该接口,因此 Any 可作为一种数据类型来看待。

    var data: Any = 12;                                     // 定义data为Any类型,默认赋值12
    
    if (data is Int64) {                                    // 判断是否是Int64类型
      log("data is Int64")                                  // 输出data is Int64
      let value = (data as Int64).getOrDefault({=> -1})     // 取出data内部的值
      log("value: ${value}")                                // 输出value: 12
    }
    
    data = 3.14                                             // 给data赋值小数
    data = true                                             // 给data赋值Bool
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10

# 1.3.2:变量声明

变量在使用前必须先声明,仓颉可以使用 varletconst 修饰符来声明一个变量,格式如下:

修饰符 变量名: 变量类型 = 初始值
修饰符 变量名 = 初始值
1
2
  1. var

    var 修饰的变量属于可变变量,允许在运行时对变量的值做修改。

    var osName: String = "OpenHarmony"
    var price1: Int64 = 5
    var price2: Float64 = 5.5
    var sum = Float64(price1) + price2
    println("操纵系统名称:${osName}")    // 操作系统名字: OpenHarmony
    println("第一个价格是:${price1}")    // 第一个价格是: 5
    println("第二个价格是:${price2}")    // 第二个价格是: 5.5
    println("总价格:${sum}")            // 总价格: 10.5
    
    price1 = 3                         // 重置price1的值
    price1 = 3.5                       // 编译报错,只能赋值Int64类型的值
    osName = "HarmonyOS"               // 重置osName的值
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
  2. let

    let 修饰的变量要求在运行时初始化完毕后不可修改。

    let age = 20                  // age初始化后不可修改
    let pi: Float64 = 3.141592653 // pi初始化后不可修改
    pi = 5                        // 编译时会报错
    
    1
    2
    3
  3. const

    const 修饰的变量要求在编译期完成求值,并且在运行时不可修改。

    const PI = 3.1415926 // 编译期确定了PI的值
    PI = 10              // 报错,不允许修改
    
    1
    2

# 1.3.3:函数

  1. 函数声明

    函数就是包裹在花括号中的代码块,前边使用 func 关键字,语法格式如下:

    func function_name() {
      // 执行代码
    }
    
    1
    2
    3

    例如声明函数如下:

    func log(msg: String) { // 声明一个函数
      println(msg);         // 代码块
    }
    
    1
    2
    3
  2. 函数调用

    函数只有通过调用才可以执行函数内的代码,语法格式如下:

    function_name()
    
    1

    样例如下:

    func log(msg: string) { // 声明一个函数
      println(msg);         // 代码块
    }
    log("Hello, 仓颉");      // 调用函数
    
    1
    2
    3
    4
  3. 函数返回值

    如果希望得到函数的执行结果,可以使用 return 语句,语法如下:

    func function_name(): return_type {
      return value;                     // return语句
    }
    
    1
    2
    3

    样例如下:

    func sayHi(): String { // 定义sayHi函数,该函数的返回类型为string
      return "Hello!" 
    }
    
    func execute() {       // 定义execute函数
      var msg = sayHi();   // 调用sayHi()函数
      log(msg);            // 打印sayHi()函数的返回值
    }
    
    execute();             // 调用execute()函数
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
  4. 带参数函数

    在调用函数时可以向函数传递值,这些值被称为参数,语法如下:

    func func_name(param1 :paramType, param2 :paramType) {
    }
    
    1
    2

    样例如下:

    func add(x: Int64, y: Int64): Int64 { // 定义add函数,该函数返回类型为nubmer, 接收两个number类型的参数x
        return x + y;
    }
    
    log("${add(1,2)}")                    // 3
    
    1
    2
    3
    4
    5
  5. 命名参数

    函数定义了参数则必须传递这些参数否则报错,如果不想传递这些参数可以使用命名参数,当不传入该参数时则使用默认值,语法如下:

    func func_name(param1: paramType, param2!: paramType = default_value) {
    }
    
    1
    2

    样例如下:

    func add(x: number = 20, y!: number = 50) { // 设置y有默认值
      return x + y;
    }
    
    log("${add(10)}");                          // y使用默认值,输出60
    log("${add(10, y: 10)}");                   // y使用10,输出20
    
    1
    2
    3
    4
    5
    6

    📢:如果参数不全是命名参数,那么命名参数的位置必须放在最后。

  6. 变长参数

    在不确定要向函数传递多个参数的情况下,可以使用变长参数,变长参数前边以 Array 表示,语法如下:

    func func_name(param1: paramType, param2: paramType, param3: Array<paramType>) {
    }
    
    1
    2

    样例如下所示:

    func add(param1: String, param2: Array<Int>): Int64 { // 变长参数
      log("add: ${param1}");
      var sum = 0
      for (e in param2) {  // 遍历剩余参数
        sum += e
      }
      return sum
    }
    
    log("${add("sum", 1, 2, 3, 4)}") // add: sum
                                     // 10
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11

# 1.3.4:类

  1. 定义类

    仓颉是面向对象的编程语言,定义一个类使用关键字 class ,类可以包含字段、构造方法和方法。语法如下:

    class class_name {
      // 类作用域
    }
    
    1
    2
    3

    样例如下:

    class Person {
      var name: String;
      var age: Int;
    
      init(name: String, age: Int) {
        this.name = name;
        this.age = age;
      }
    
      func info(): String {
        return "name: ${this.name}, age: ${this.age}";
      }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
  2. 创建类对象

    类定义完后,可以通过 类名(args) 的格式实例化一个类的对象,实例化类对象即调用类的构造方法,语法如下:

    var object_name = class_name([ args ])
    
    1

    样例如下:

    var person = Person('张三', 20); // 创建一个Person对象
    
    1
  3. 访问类属性和方法

    访问类的属性和方法以 . 号的形式,语法如下:

    obj.field_name      // 访问属性
    obj.function_name() // 访问方法
    
    1
    2

    样例如下:

    var person = Person('harmony', 10); // 创建一个person
    
    log(person.name);                   // harmony
    log("${person.age}");               // 10
    log(person.info());                 // name: harmony, age: 10
    
    1
    2
    3
    4
    5
  4. 类的继承

    仓颉支持继承类,创建类的时候可以使用字 <: 符号继承一个已有的类,这个已有的类称为父类,继承它的类称为子类。子类除了不能继承父类的私有成员(方法和属性)和构造函数,其他的都可以继承。语法如下:

    class child_class_name <: parent_class_name {
    }
    
    1
    2

    样例如下:

    open class Person { // 父类使用open关键字修饰,表示允许子类继承
        var name: String
        var age: Int
        
        init(name: String, age: Int) {
        this.name = name
        this.age = age
        }
        
        func info(): String {
            return "name: ${this.name}, age: ${this.age}"
        }
    }
    
    class Zhangsan <: Person { // 子类继承父类
        init(name: String, age: Int) {
            super(name, age)
        }
        func sayHello() {
            println("Hello")
        }
    }
    
    
    var person = Child("张三", 20); // 创建一个person
    person.sayHello()              // Hello
    log(person.name);              // 张三
    log("${person.age}");          // 20
    log(person.info());            // name: harmony, age: 20
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29

    📢:父类必须使用 open 关键字修饰,并且类的继承只支持单继承,不支持多继承。也就是说子类只能继承一个父类。

  5. 方法重写

    子类可以重写父类的方法,在重写父类方法的时候也可以使用 super 关键字调用父类的方法。样例如下:

    open class Person { // 父类使用open关键字修饰,表示允许子类继承
        var name: String
        var age: Int
        
        init(name: String, age: Int) {
          this.name = name
          this.age = age
        }
        
        func info(): String {
          return "name: ${this.name}, age: ${this.age}"
        }
    }
    
    class Zhangsan <: Person {         // 子类继承父类
        init(name: String, age: Int) {
            super(name, age)           // 使用super调用父类构造方法
        }
        func sayHello() {
            println("Hello")
        }
    }
    
    
    var person = Child("张三", 20); // 创建一个person
    person.sayHello()              // Hello
    log(person.name);              // 张三
    log("${person.age}");          // 20
    log(person.info());            // name: harmony, age: 20
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
  6. 访问修饰符

    仓颉提供了访问控制符来保护对类、变量、方法和构造方法的访问。它支持 4 种不同的访问权限。

    • internal(默认):受保护,仅当前包及子包内访问。

    • protected:受保护,只能在当前模块和其子类访问。

    • private:私有,只能在 class 内访问。

    • public:公有,可以在任何地方被访问。

      样例如下所示:

      class Person {
        var name: String;
        private var age: Int;             // age为private,外界无法访问
      
        init(name: String, age: Int) {
          this.name = name;
          this.age = age;
        }
      
        func info(): String {
          return "name: ${this.name}, age: ${this.age}"
        }
      }
      
      var person = Person('harmony', 10); // 创建Person对象
      log(person.name);                   // harmony
      log("${person.age}");               // 编译报错,age为private
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17

# 1.2.5:接口

  1. 定义接口

    接口是一系列抽象方法的声明,接口定义后需要具体的类实现,语法如下:

    interface interface_name {
      // 抽象方法
    }
    
    1
    2
    3

    样例如下:

    interface IPerson {              // 定义一个接口
      func say(): Unit               // 定义say方法,该方法默认是public,返回值为Unit类型
    }
    
    1
    2
    3
  2. 接口继承

    接口可以使用 <: 符号继承其它接口来扩展自己,接口既支持单继承又支持多继承,多继承时接口间使用逗号 & 分隔。语法如下:

    // 接口单继承
    interface Child_interface_name <: super_interface_name {
    }
    
    // 接口多继承
    interface Child_interface_name <: super_interface_name1 & super_interface_name2 {
    }
    
    1
    2
    3
    4
    5
    6
    7

    样例如下:

    interface IPlay {                    // 定义IPlay接口
      func play(): Unit
    }
    
    interface IRun {                     // 定义IRun接口
      func run(): Unit
    }
    
    interface ITeacher <: IPlay & IRun { // 定义ITeacher接口,并继承IPlay和IRun接口
      func teach(): Unit
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
  3. 类实现接口

    类可以使用 <: 关键字实现一个接口,一个类实现接口后必须实现接口定义的方法,语法如下:

    class class_name <: interface_name {
    }
    
    1
    2

    样例如下所示:

    interface IPlay {                    // 定义IPlay接口
      func play(): Unit                  // 定义play方法
    }
    
    interface IRun {                     // 定义IRun接口
      func run(): Unit                   // 定义run方法
    }
    
    interface ITeacher <: IPlay & IRun { // 定义ITeacher接口并继承IPlay和IRun接口
      func teach(): Unit                 // 定义teach方法
    }
    
    class Teacher <: ITeacher {          // 类Teacher实现ITeacher接口
      public func teach(): Unit {        // 实现方法
        println("teach")
      }
        
      public func play(): Unit {         // 实现方法
        log("play")
      }
      
      public func run(): Unit {          // 实现方法
        log("run")
      }
    }
    
    let teacher = Teacher()              // 创建Teacher实例
    teacher.play()                       // 输出play
    teacher.run()                        // 输出run
    teacher.teach()                      // 输出teach
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30

# 1.2.6:扩展

  1. 直接扩展

    仓颉支持对已经存在的类做直接扩展,常用在扩展方法的场景,语法如下:

    extend class_name {
      func func_name(): return_type {} // 添加扩展方法
    }
    
    1
    2
    3

    样例如下:

    class Teacher {                                    // 定义Teacher类
      public var name: String                          // 添加name属性
      public var age: Int                              // 添加age属性
      
      init(name!: String = "lisi", age!: Int64 = 30) { // 添加构造方法并初始化属性
        this.name = name
        this.age = age
      }
      
      func teach(): Unit {                             // 添加teach方法
        println("teach")
      }
    }
    
    extend Teacher {                                   // 对Teacher进行扩展
      func updateInfo(name: String, age: Int): Unit {  // 给Teacher添加updateInfo()方法
        this.name = name
        this.age = age
      }
      
      func printInfo() {                               // 给Teacher添加printInfo()方法
        println("teacher info, name = ${this.name}, age = ${this.age}")
      }
    }
    
    let teacher = TeacherA()
    teacher.printInfo()            // teacher info, name = lisi, age = 30
    teacher.updateInfo("lisi", 18) // 更改信息
    teacher.printInfo()            // teacher info, name = lisi, age = 18
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
  2. 接口扩展

    仓颉支持对已经存在的类做接口扩展,它既可以扩展方法,也可以扩展属性,步骤如下:

    • 定义接口

      interface class_name {
        func method_name(): return_type
        mut prop prop_name: prop_type
        prop prop_name: prop_type
      }
      
      1
      2
      3
      4
      5

      样例如下所示:

      interface IInfo {          // 定义IInfo接口
        func info(): Unit        // 定义info方法
        mut prop address: String // 定义address属性
        prop email: String       // 定义email属性
      }
      
      1
      2
      3
      4
      5

      📢:此处的mut表示允许给addres赋值,

    • 实现扩展

      extend class_name <: interface_name {
        public mut prop prop_name: prop_type {
        	get() {
        	  prop_type
        	}
        	set(value) {
        	  // 赋值操作,此处有疑问???
        	}
        }
      
        public prop prop_name: prop_type {
        	get() {
        	  prop_type
        	}
        }
        
        public func func_name(): return_type {
        }
      }
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19

      样例如下所示:

      extend TeacherA <: IInfo {
        public mut prop address: String {
          get() {
            "Beijing"
          }
          set(value) {
            address = value
          }
        }
        public func info(): Unit {
          println("teacher info, name = ${this.name}, age = ${this.age}, address = ${address}")
        }
      }
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13

    完整样例如下所示:

    package arkui_cj
    
    class TeacherA {
      public var name: String
      public var age: Int
      
      init(name!: String = "lisi", age!: Int64 = 30) {
        this.name = name
        this.age = age
      }
      
      func teach(): Unit {
        println("teach")
      }
    }
    
    extend TeacherA {
      func updateInfo(name: String, age: Int): Unit {
        this.name = name
        this.age = age
      }
      
      func printInfo() {
        println("teacher info, name = ${this.name}, age = ${this.age}")
      }
    }
    
    interface IInfo {
      func info(): Unit
      mut prop address: String
      prop email: String
    }
    
    extend TeacherA <: IInfo {
      public mut prop address: String {
        get() {
          "Beijing"
        }
        set(value) {
          address = value
        }
      }
      
      public prop email: String {
        get() {
          "arkui.club@cj.com"
        }
      }
      
      public func info(): Unit {
        println("teacher info, name = ${this.name}, age = ${this.age}, address = ${address}")
      }
    }
    
    main(): Int64 {
      let teacher = TeacherA()
      teacher.teach()
      teacher.printInfo()
      teacher.updateInfo("Zhangsan", 18)
      teacher.printInfo()
      teacher.info()
      teacher.address = "Shanghai"
      teacher.info()
      println(teacher.email)
      return 0
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66

# 1.2.7:小结

本节简单介绍了仓颉基础语法部分,掌握这些基础部分可以支撑日常简单应用开发了,对于仓颉更多其它用法读者请参考官网 (opens new window)

请作者喝杯咖啡

津公网安备 12011402001367号

津ICP备2020008934号-2

中央网信办互联网违法和不良信息举报中心

天津市互联网违法和不良信息举报中心