HarmonyOS开发基础 --鸿蒙仓颉语言基础语法入门
仓颉编程语言是华为自主研发的一种面向全场景应用开发的现代编程语言,具有高效编程、安全可靠、轻松并发和卓越性能等特点。本节将简单介绍仓颉语言的部分语法和使用,帮助开发者快速上手。
1.3.1:数据类型
- 整数
仓颉把整数分为有符号和无符号两种类型,有符号整数用 Int8
、Int16
、Int32
、Int64
和 IntNative
来表示,无符号整数用 UInt8
、UInt16
、UInt32
、UInt64
和 UIntNative
来表示。
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类型
}
📢:具体使用哪种类型取决于该程序中需要处理的整数的性质和范围。在 Int64
类型适合的情况下,首选 Int64
类型。具体范围可参见官网。
- 小数
仓颉提供了 Float16
、Float32
和 Float64
分别表示编码长度为 16-bit
、 32-bit
和 64-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
}
📢:在多种浮点类型都适合的情况下,首选精度高的浮点类型 Float64
。具体范围可参见官网。
- Bool
仓颉提供了 Bool
关键字来表示逻辑值 true
和 false
。
let a: Bool = true
let b: Bool = false
- 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")
}
- String
仓颉提供了 String
关键字来表示字符串类型,使用单引号('
)或双引号("
)来表示字符串类型,同时支持插值字符串的表达形式,如 ${a + b}
。
let fruit = "apples"
let count = 10
let s = "There are ${count * count} ${fruit}"
- 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}")
}
- 元组
仓颉提供了元组来表示已知元素数量和类型的数组,元组内的各元素的类型不必相同,但是对应位置的类型必须一致。
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
- Unit
Unit
是一种特殊的数据类型,适用于只关心副作用而不关心值的表达式,例如,println
函数、赋值表达式、复合赋值表达式、自增和自减表达式、循环表达式,它们的类型都是 Unit
。
main(): Int64 {println("unit")testUnit()return 0
}func testUnit(): Unit {var age = 20age++
}
- Any
仓颉提供了 Any
接口,它是一个空实现,所有数据均实现了该接口,因此 Any
可作为一种数据类型来看待。
var data: Any = 12; // 定义data为Any类型,默认赋值12if (data is Int64) { // 判断是否是Int64类型log("data is Int64") // 输出data is Int64let value = (data as Int64).getOrDefault({=> -1}) // 取出data内部的值log("value: ${value}") // 输出value: 12
}data = 3.14 // 给data赋值小数
data = true // 给data赋值Bool
1.3.2:变量声明
变量在使用前必须先声明,仓颉可以使用 var
、let
、const
修饰符来声明一个变量,格式如下:
修饰符 变量名: 变量类型 = 初始值
修饰符 变量名 = 初始值
- 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.5price1 = 3 // 重置price1的值
price1 = 3.5 // 编译报错,只能赋值Int64类型的值
osName = "HarmonyOS" // 重置osName的值
- let
let
修饰的变量要求在运行时初始化完毕后不可修改。
let age = 20 // age初始化后不可修改
let pi: Float64 = 3.141592653 // pi初始化后不可修改
pi = 5 // 编译时会报错
- const
const
修饰的变量要求在编译期完成求值,并且在运行时不可修改。
const PI = 3.1415926 // 编译期确定了PI的值
PI = 10 // 报错,不允许修改
1.3.3:函数
- 函数声明
函数就是包裹在花括号中的代码块,前边使用 func
关键字,语法格式如下:
func function_name() {// 执行代码
}
例如声明函数如下:
func log(msg: String) { // 声明一个函数println(msg); // 代码块
}
- 函数调用
函数只有通过调用才可以执行函数内的代码,语法格式如下:
function_name()
样例如下:
func log(msg: String) { // 声明一个函数println(msg); // 代码块
}
log("Hello, 仓颉"); // 调用函数
- 函数返回值
如果希望得到函数的执行结果,可以使用 return
语句,语法如下:
func function_name(): return_type {return value; // return语句
}
样例如下:
func sayHi(): String { // 定义sayHi函数,该函数的返回类型为stringreturn "Hello!"
}func execute() { // 定义execute函数var msg = sayHi(); // 调用sayHi()函数log(msg); // 打印sayHi()函数的返回值
}execute(); // 调用execute()函数
- 带参数函数
在调用函数时可以向函数传递值,这些值被称为参数,语法如下:
func func_name(param1: paramType, param2: paramType) {
}
样例如下:
func add(x: Int64, y: Int64): Int64 { // 定义add函数,该函数返回类型为nubmer, 接收两个number类型的参数xreturn x + y;
}log("${add(1,2)}") // 3
- 命名参数
函数定义了参数则必须传递这些参数否则报错,如果不想传递这些参数可以使用命名参数,当不传入该参数时则使用默认值,语法如下:
func func_name(param1: paramType, param2!: paramType = default_value) {
}
样例如下:
func add(x: Int64 = 20, y!: Int64 = 50) { // 设置y有默认值return x + y;
}log("${add(10)}"); // y使用默认值,输出60
log("${add(10, y: 10)}"); // y使用10,输出20
📢:如果参数不全是命名参数,那么命名参数的位置必须放在最后。
- 变长参数
在不确定要向函数传递多个参数的情况下,可以使用变长参数,变长参数前边以 Array
表示,语法如下:
func func_name(param1: paramType, param2: paramType, param3: Array<paramType>) {
}
样例如下所示:
func add(param1: String, param2: Array<Int64>): Int64 { // 变长参数log("add: ${param1}");var sum = 0for (e in param2) { // 遍历剩余参数sum += e}return sum
}log("${add("sum", 1, 2, 3, 4)}") // add: sum// 10
1.3.4:类
- 定义类
仓颉是面向对象的编程语言,定义一个类使用关键字 class
,类可以包含字段、构造方法和方法。语法如下:
class class_name {// 类作用域
}
样例如下:
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}";}
}
- 创建类对象
类定义完后,可以通过 类名(args)
的格式实例化一个类的对象,实例化类对象即调用类的构造方法,语法如下:
var object_name = class_name([ args ])
样例如下:
var person = Person('张三', 20); // 创建一个Person对象
- 访问类属性和方法
访问类的属性和方法以 .
号的形式,语法如下:
obj.field_name // 访问属性
obj.function_name() // 访问方法
样例如下:
var person = Person('harmony', 10); // 创建一个personlog(person.name); // harmony
log("${person.age}"); // 10
log(person.info()); // name: harmony, age: 10
- 类的继承
仓颉支持继承类,创建类的时候可以使用 <:
符号继承一个已有的类,这个已有的类称为父类,继承它的类称为子类。子类除了不能继承父类的私有成员(方法和属性)和构造函数,其他的都可以继承。语法如下:
class child_class_name <: parent_class_name {
}
样例如下:
open class Person { // 父类使用open关键字修饰,表示允许子类继承var name: Stringvar age: Intinit(name: String, age: Int) {this.name = namethis.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 = Zhangsan("张三", 20); // 创建一个person
person.sayHello() // Hello
log(person.name); // 张三
log("${person.age}"); // 20
log(person.info()); // name: 张三, age: 20
📢:父类必须使用 open
关键字修饰,并且类的继承只支持单继承,不支持多继承。也就是说子类只能继承一个父类。
- 方法重写
子类可以重写父类的方法,在重写父类方法的时候也可以使用 super
关键字调用父类的方法。样例如下:
open class Person { // 父类使用open关键字修饰,表示允许子类继承var name: Stringvar age: Intinit(name: String, age: Int) {this.name = namethis.age = age}func info(): String {return "name: ${this.name}, age: ${this.age}"}
}class Zhangsan <: Person { // 子类继承父类init(name: String, age: Int) {super(name, age)}override func info(): String { // 重写父类方法return "Hello, " + super.info() // 调用父类方法}
}var person = Zhangsan("张三", 20); // 创建一个person
log(person.info()); // Hello, name: 张三, age: 20
- 访问修饰符
仓颉提供了访问控制符来保护对类、变量、方法和构造方法的访问。它支持 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.3.5:接口
- 定义接口
接口是一系列抽象方法的声明,接口定义后需要具体的类实现,语法如下:
interface interface_name {// 抽象方法
}
样例如下:
interface IPerson { // 定义一个接口func say(): Unit // 定义say方法,该方法默认是public,返回值为Unit类型
}
- 接口继承
接口可以使用 <:
符号继承其它接口来扩展自己,接口既支持单继承又支持多继承,多继承时接口间使用逗号 &
分隔。语法如下:
// 接口单继承
interface Child_interface_name <: super_interface_name {
}// 接口多继承
interface Child_interface_name <: super_interface_name1 & super_interface_name2 {
}
样例如下:
interface IPlay { // 定义IPlay接口func play(): Unit
}interface IRun { // 定义IRun接口func run(): Unit
}interface ITeacher <: IPlay & IRun { // 定义ITeacher接口,并继承IPlay和IRun接口func teach(): Unit
}
- 类实现接口
类可以使用 <:
关键字实现一个接口,一个类实现接口后必须实现接口定义的方法,语法如下:
class class_name <: interface_name {
}
样例如下所示:
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.3.6:扩展
- 直接扩展
仓颉支持对已经存在的类做直接扩展,常用在扩展方法的场景,语法如下:
extend class_name {func func_name(): return_type {} // 添加扩展方法
}
样例如下:
class Teacher { // 定义Teacher类public var name: String // 添加name属性public var age: Int // 添加age属性init(name!: String = "lisi", age!: Int64 = 30) { // 添加构造方法并初始化属性this.name = namethis.age = age}func teach(): Unit { // 添加teach方法println("teach")}
}extend Teacher { // 对Teacher进行扩展func updateInfo(name: String, age: Int): Unit { // 给Teacher添加updateInfo()方法this.name = namethis.age = age}func printInfo() { // 给Teacher添加printInfo()方法println("teacher info, name = ${this.name}, age = ${this.age}")}
}let teacher = Teacher()
teacher.printInfo() // teacher info, name = lisi, age = 30
teacher.updateInfo("lisi", 18)// 更改信息
teacher.printInfo() // teacher info, name = lisi, age = 18
- 接口扩展
仓颉支持对已经存在的类做接口扩展,它既可以扩展方法,也可以扩展属性,步骤如下:
-
定义接口
interface interface_name {func method_name(): return_typemut prop prop_name: prop_typeprop prop_name: prop_type }
样例如下所示:
interface IInfo { // 定义IInfo接口func info(): Unit // 定义info方法mut prop address: String // 定义address属性prop email: String // 定义email属性 }
📢:此处的
mut
表示允许给address
赋值。 -
实现扩展
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 {} }
样例如下所示:
extend Teacher <: 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}")} }
完整样例如下所示:
package arkui_cjclass TeacherA {public var name: Stringpublic var age: Intinit(name!: String = "lisi", age!: Int64 = 30) {this.name = namethis.age = age}func teach(): Unit {println("teach")}
}extend TeacherA {func updateInfo(name: String, age: Int): Unit {this.name = namethis.age = age}func printInfo() {println("teacher info, name = ${this.name}, age = ${this.age}")}
}interface IInfo {func info(): Unitmut prop address: Stringprop 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.3.7:小结
本节简单介绍了仓颉基础语法部分,掌握这些基础部分可以支撑日常简单应用开发了。对于仓颉更多其它用法,读者请参考官网。
通过以上介绍,希望你对仓颉编程语言有了一个初步的了解,并能够开始编写简单的HarmonyOS应用。随着你对仓颉的深入学习,你将能够更高效地利用其强大功能,开发出更加丰富和高质量的应用。