目录

类型扩展

核心概念

特殊符号

1. 类型扩展是什么

2. 能做哪些扩展

3. 代码示例讲解

类型推断(Type Inference)

1. 变量类型推断

2. 函数返回值推断

3. 泛型函数类型推断

4. 匿名函数(Lambda)类型推断

为什么重要?


类型扩展

核心概念
  • 不修改原代码扩展类型:通过 extend 关键字为已有类型(如系统类型、第三方库类型)添加新功能,无需继承或修改原类型定义。
  • 支持扩展的内容
    • 成员函数
    • 属性
    • 操作符重载
    • 接口实现
特殊符号
  • extend 关键字:声明类型扩展
  • <: 符号:实现接口(在扩展中使用)
1. 类型扩展是什么

在仓颉语言里,类型扩展就是不用去改动原来类型的代码,就能给这个类型增加新东西,比如新的函数、属性,还能让它实现新的接口。就好像你有一个玩具车,它原来只有前进后退功能,通过类型扩展,就可以给它增加灯光、音乐这些新功能,但是不用拆开玩具车去改里面原来的构造。

2. 能做哪些扩展
  • 添加函数:可以给已有的类型增加新的函数。比如给 String 类型增加一个能打印它长度的函数。
  • 添加属性:虽然前面代码示例没体现,但理论上可以给类型增加新的属性。就像给一个人物角色类型,增加 “经验值” 这样的属性。
  • 添加操作符重载:能让已有的操作符对这个类型有新的运算规则。比如让 “+” 号对特定类型有不同于常规的相加方式。
  • 实现接口:可以让已有的类型去实现新的接口,让它具备接口规定的一些能力。
3. 代码示例讲解
  • 给 String 类型添加函数
extend String {
    func printSize() {
        print(this.size)
    }
}

"123".printSize() // 3

这里 extend String 意思是要对 String 类型进行扩展。然后在大括号里定义了一个 printSize 函数。this 就代表调用这个函数的具体 String 实例,像这里 "123" 就是那个实例,this.size 就是获取这个字符串的长度,然后用 print 把长度打印出来,所以运行 "123".printSize() 就会输出 3 。

  • 让整数类型实现接口
sealed interface Integer {}

extend Int8 <: Integer {}
extend Int16 <: Integer {}
extend Int32 <: Integer {}
extend Int64 <: Integer {}

let a: Integer = 123 // ok

首先 sealed interface Integer {} 定义了一个 Integer 接口,sealed 修饰符表示这个接口只能在当前包里面被实现或者扩展,就好像给这个接口画了个 “势力范围”,不能跑出去被实现。然后 extend Int8 <: Integer {} 这些代码,就是让 Int8Int16Int32Int64 这些整数类型去实现 Integer 接口。这样一来,整数类型就好像拿到了 Integer 接口给的 “通行证”,可以被当成 Integer 类型来用了,所以 let a: Integer = 123 这样写是没问题的,因为 123 一般是 Int32 类型,而 Int32 已经实现了 Integer 接口。

类型推断(Type Inference)

核心概念
编译器自动分析代码上下文,推导出变量、函数返回值、泛型参数等的类型,减少手动编写类型的工作量,同时保证类型安全。就像你给朋友描述一个物品,朋友根据你的描述就能知道具体是什么,不需要你明确说出它的名字。

1. 变量类型推断

规则:根据变量的初始值自动推断类型,无需显式声明。
例子

var score = 95           // 自动推断为整数类型(Int64)
var message = "你好"     // 自动推断为字符串类型(String)
var isReady = false      // 自动推断为布尔类型(Bool)

说明

  • 比如 score = 95 中,95 是数字,所以编译器知道 score 是整数;message = "你好" 里有引号,自然是字符串。
  • 一旦推断完成,变量类型就固定了,比如 score 只能存整数,不能突然存字符串。
2. 函数返回值推断

规则

  • 如果函数没写返回类型,编译器会看函数最后一句代码的类型,作为返回值类型。
    例子
// 显式写法:明确返回 Int 类型
func multiply(a: Int, b: Int): Int { 
    a * b  // 返回的是整数,和声明的 Int 一致
}

// 隐式写法:省略返回类型,自动推断为 Int
func divide(a: Int, b: Int) { 
    a / b  // 最后一句是除法运算,结果是整数,所以返回 Int
}

注意

  • 如果函数没有返回值(比如只打印内容),需要显式声明返回类型为 Unit(类似其他语言的 void)。
3. 泛型函数类型推断

规则

  • 调用泛型函数时,编译器会根据传入的参数类型,自动推断泛型参数(比如 <T> 代表什么类型)。
  • 复杂场景(如函数套函数、匿名函数参数)也能推断。

例子 1:简单泛型函数

// 泛型函数:参数和返回值都是 T 类型
func getFirst<T>(items: [T]): T { 
    items[0]  // 返回第一个元素,类型由 items 推断
}

let numbers = [1, 2, 3]
let firstNum = getFirst(numbers)  // 推断 T 为 Int64,因为 numbers 是整数数组

例子 2:复杂泛型函数(map 函数)

// 泛型函数:将数组中的每个元素按函数 f 处理,返回新数组
func map<T, R>(f: (T) -> R, array: [T]): [R] { 
    return array.map(f)  // 遍历数组,应用函数 f
}

// 调用时自动推断:T 是 Int,R 是 String(因为把整数转成字符串)
let result = map(f: { i in i.toString() }, array: [4, 5, 6]) 
// 等价于 map<Int, String>(...),无需手动写 <Int, String>

推断逻辑

  • { i in i.toString() } 里的 i.toString() 说明 i 是整数(能调用转字符串的函数),所以 T 是 Int,返回值 R 是 String
  • array: [4,5,6] 是整数数组,验证了 T 是 Int,所以整个函数的类型就确定了。
4. 匿名函数(Lambda)类型推断

规则

  • 匿名函数的参数类型由上下文推断,不用显式写类型(比如函数参数要求什么类型,这里就推断为什么类型)。
    例子
// 定义一个函数,接受一个把 Int 转为 String 的函数作为参数
func process(f: (Int) -> String) { 
    let result = f(100)  // 传入的函数需要能处理 Int
    print(result)
}

// 调用时直接写函数逻辑,编译器推断参数 x 是 Int
process(f: { x in x.toString() + "分" }) 
// 等价于 { x: Int in x.toString() + "分" },省略了类型声明
类型推断为什么重要?优势在哪里?
  • 少写代码:比如 var x = 5 比 var x: Int = 5 更简洁,尤其代码量大时能省很多精力。
  • 避免错误:编译器保证类型正确,比如不会把字符串当成数字用,运行时不容易出错。
  • 专注逻辑:不用花时间想变量该声明成什么类型,直接写值就行,开发更快。
Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐