仓颉语言核心类型:struct 结构体
struct是一种值类型,而class是引用类型。这意味着当你把一个struct实例赋值给一个新变量时,会创建该实例的一个完整副本。而class的赋值,则是让新变量引用同一个对象实例。struct支持成员变量、成员函数、构造函数、属性等完整的面向对象能力,但不支持继承(Class 支持继承),适用于定义轻量级的数据载体(如坐标、尺寸、用户信息等)。struct 定义语法struct类型的定义以关键
目录
在仓颉语言中,struct(结构体) 是用于构建数据模型的核心值类型,相比类(Class),它更轻量、高效,专注于数据封装与值传递。作为鸿蒙原生开发的重要基石,struct 支持自定义方法、属性访问、可变控制等特性,同时在内存布局和性能优化上独具优势。
1.struct 核心概念与定义
struct是一种值类型,而class是引用类型。这意味着当你把一个struct实例赋值给一个新变量时,会创建该实例的一个完整副本。而class的赋值,则是让新变量引用同一个对象实例。struct支持成员变量、成员函数、构造函数、属性等完整的面向对象能力,但不支持继承(Class 支持继承),适用于定义轻量级的数据载体(如坐标、尺寸、用户信息等)。
struct 定义语法
struct 类型的定义以关键字 struct 开头,后跟 struct 的名字,接着是定义在一对花括号中的 struct 定义体。struct 定义体中可以定义一系列的成员变量、成员属性、静态初始化器、构造函数和成员函数。
示例:定义一个Employee结构体
public struct Employee {
// 可变的实例变量
var name: String
// 不可变的实例变量
let id: Int64
// 静态变量
private static var employeeCount: Int64 = 0
// 静态构造函数,用于初始化静态成员
static init() {
employeeCount = 0
println("静态构造函数被调用,初始化员工计数。")
}
// 构造函数
public init(name: String, id: Int64) {
this.name = name
this.id = id
employeeCount++
}
// 一个普通方法
public func displayInfo() {
println("员工ID: ${id}, 姓名: ${name}")
}
// 静态方法
public static func getCount(): Int64 {
return employeeCount
}
// 可变方法,可以修改 var 声明的实例变量
public mut func changeName(newName: String) {
this.name = newName
}
}
2.struct 实例化
仓颉的 struct 定义需遵循成员变量必须初始化原则,支持两种初始化方式:直接赋值 或 构造函数赋值,且结构体的构造函数分为【主构造函数】和【普通构造函数】,有明确的语法约束。
示例:User 结构体
package jk0909demo.chapter2
public struct User {
//定义变量,有两种初始化机制,必须要赋值
//1.直接赋值
//2.通过构造函数赋值
protected var name: String
protected var phone: String
// 主构造函数只能有一个
public User(name: String, phone: String) {
this.name = name
this.phone = phone
println("姓名为:${this.name},手机号码为:${this.phone}")
}
// 普通构造函数:用init关键字,支持无参/单参等不同参数列表
public init() {
this.name = "薄荷"
this.phone = "123456789"
println("姓名为:${this.name},手机号码为:${this.phone}")
}
// 重载普通构造函数:参数列表需与其他构造函数不同
public init(name: String) {
this.name = name
this.phone = "13913321086"
println("姓名为:${this.name},手机号码为:${this.phone}")
}
}
代码解析:
- 成员变量
name/phone未直接赋值,因此必须通过构造函数完成初始化,否则编译报错 - 主构造函数(
public User(...))是结构体的核心构造逻辑,仅能定义一个 - 普通构造函数(
init)可重载,但需保证参数列表唯一(个数 / 类型不同) - 构造函数内通过
this关键字访问当前实例的成员变量
package jk0908demo
//导入包
import jk0908demo.chapter2.User
//仓颉是个多范式的语言,多种语法组成,轻量级
main() {
//创建Struct实例对象,变量名称: struct的名 = struct的名()
//()依赖Struct提供的构造函数
var s1: User = User()
var s2: User = User("茉莉1")
var s3: User = User("茉莉2","987654321")
}
运行结果:

3.构造函数的调用约束
仓颉对struct 构造函数的相互调用有严格限制:主构造函数不能调用其他构造函数,普通构造函数可调用本结构体的其他构造函数。
示例:Stu 结构体(构造函数调用规则)
package jk0909demo.chapter3
public struct Stu{
var a1 :Int64
// 主构造函数:禁止调用this()访问其他构造函数
public Stu(str:String)
{
// this(10) // 编译报错:主构造函数不能通过this()调用其他构造函数
this.a1 = 100
}
// 普通构造函数1:单参初始化
public init(a1:Int64)
{
this.a1 = a1
}
// 普通构造函数2:无参,可调用其他构造函数
public init()
{
this(10) // 普通构造函数中可以使用this()调用本结构体的其它构造函数
this.a1 =200
println("a1的值为:${a1}")
}
}
package jk0908demo
//导入包
import jk0908demo.chapter3.Stu
main() {
var s:Stu =Stu()
}
运行结果:

4.静态成员变量与静态构造函数
struct 支持静态成员变量和静态构造函数,静态成员属于结构体本身(而非实例),用于存储全局共享数据,静态构造函数专门初始化静态变量。
示例:Emp 结构体(静态成员演示)
package jk0909demo.chapter5
public struct Emp{
// 实例变量:需实例化结构体后才能访问
public var name : String
// 静态变量:属于结构体,所有实例共享
public static var count :Int64
// 静态构造函数:无参数,仅初始化静态变量,不能用this
static init()
{
count = 200
}
// 实例构造函数:初始化实例变量
public Emp()
{
this.name = "张三"
}
}
代码解析:
- 静态变量
count需通过static init()初始化,静态构造函数无参数、不能使用 this 关键字、且不能被访问修饰符修饰,函数体中必须完成对所有未初始化的静态成员变量的初始化,否则编译报错。 - 访问方式区分:
- 实例变量:
let emp = Emp(); emp.name;【通过创建的实例名去访问】 - 静态变量:
Emp.count【无需实例化,直接通过结构体名访问】
- 实例变量:
- 静态构造函数在结构体首次被使用时自动执行,且仅执行一次。
package jk0908demo
//导入包
import jk0908demo.chapter5.Emp
main() {
println("count的值为:${Emp.count}")
var emp:Emp = Emp()
println("name的值为:${emp.name}")
}
运行结果:

5.struct 的核心特性:值传递
仓颉中 struct 是值类型,Class 是引用类型,最核心的区别体现在赋值 / 传参时的行为:struct 赋值会拷贝完整数据,Class 赋值仅传递内存引用。
示例:值传递 vs 引用传递对比
【struct值传递】
package jk0909demo.chapter6
public struct Employee{
var name: String
public Employee(){
this.name = "QQ"
}
public init(name: String){
this.name = name
}
public func execEmployee(){
var emp1: Employee = Employee("福西西")
println("现在的姓名为:${emp1.name}") // 输出:福西西
var emp2 = emp1 // 拷贝emp1的完整数据,emp2是新实例
emp2.name = "阿信"
println("现在的姓名为:${emp1.name}") // 输出:福西西(emp1不受影响)
}
}
【class引用传递】
package jk0909demo.chapter6
public class Employee1{
var name: String
public Employee1(){
this.name = "QQ"
}
public init(name: String){
this.name = name
}
public func execEmployee1(){
var emp1: Employee1 = Employee1("福西西")
println("现在的姓名是${emp1.name}") // 输出:福西西
var emp2 = emp1 // 传递引用,emp2和emp1指向同一实例
emp2.name = "阿信"
println("现在的姓名是${emp1.name}") // 输出:阿信(emp1被修改)
}
}
值传递 vs 引用传递
| 类型 | 赋值行为 | 内存存储 | 修改影响 |
|---|---|---|---|
| struct | 拷贝完整数据,生成新实例 | 栈内存 | 新实例修改不影响原实例 |
| class | 传递引用,指向同一实例 | 堆内存 | 新引用修改会影响原实例 |
6.struct 的可变控制:mut 关键字与属性设计器
6.1 mut 关键字:修改实例变量的必要条件
struct 的普通实例方法默认不能修改成员变量,必须添加mut关键字声明为【可变方法】,才能修改实例变量的值。
示例:mut 方法修改实例成员变量
package jk0909demo.chapter7
// 简化示例:mut方法的基础使用
public struct Emp1 {
var count: Int64 = 0
// 可变方法:加mut才能修改实例变量
public mut func add() {
this.count += 1
}
}
public func execEmp1() {
var emp1: Emp1 = Emp1()
emp1.add()
println("count的值为:${emp1.count}") // 输出:1
}
6.2 属性设计器
仓颉不推荐使用 Java 风格的setXXX/getXXX方法封装成员变量,而是提供属性设计器(Prop),通过get/set实现成员变量的安全访问,同时强化封装性。
示例:Emp1 结构体(属性设计器)实践
package jk0909demo.chapter7
public struct Emp1{
// 私有成员变量:禁止外部直接访问,强化封装
private var count: Int64 = 200
// 属性设计器
public mut prop PropCount: Int64{ //注意这里没有()
get(){
this.count
}
set(newcount){
this.count = newcount
}
}
}
public func execEmp1(){
var emp1: Emp1 = Emp1()
// emp1.count // 编译报错:private变量禁止直接访问,私有的目的是封装,封装的作用是加强访问的安全性
println(emp1.PropCount) // 调用get(),输出:200
emp1.PropCount = 400 // 调用set(),修改count为400
println(emp1.PropCount) // 输出:400
}
代码解析:
- 私有成员变量
count被private修饰,外部无法直接访问,保证数据安全 - 属性设计器
PropCount是对外的访问入口,mut修饰表示支持写入操作 get()方法负责返回成员变量值,set(newcount)方法负责接收外部传入的值并赋值给count- 调用方式:读取
emp1.PropCount等价于执行get(),赋值emp1.PropCount = 400等价于执行set(400)
package jk0909demo
// 导入包
import jk0909demo.chapter7.execEmp1
main(){
execEmp1()
}
运行结果:

7.struct 综合实践
以下整合前文所有知识点,实现一个包含【静态变量、随机数、属性设计器、构造函数】的完整 Struct 案例:
package jk0909demo.chapter8
import std.random.Random
public struct User{
// 姓名 可变变量
private var name: String
// 随机数 不可变变量
private let r1 = Random()
// 用户数量 静态变量(全局共享)
private static var cn: Int64
// 静态构造函数,只能初始化静态变量,不能有this关键字
static init(){
cn = 0
}
// 主构造函数:初始化姓名,生成随机年龄,统计用户数量
public User(name: String){
this.name = name
var age = this.r1.nextInt16(100) // 生成0-99的随机整数
cn++ // 静态变量自增,统计用户数
println("用户的姓名为:${this.name},年龄为:${age},用户的数量为:${cn}")
}
// 属性设计器:封装name的读写
public mut prop PropName: String{
get(){
this.name
}
set(newName){
this.name = newName
}
}
}
public func execUser(){
var u1: User = User("QQ")
var u2: User = User("Jasmine")
println(u1.PropName)
println(u2.PropName)
u1.PropName = "WW"
println(u1.PropName)
}
package jk0909demo
// 导入包
import jk0909demo.chapter8.execUser
main(){
execUser()
}
运行结果:

核心知识点总结:
- 构造函数规则:主构造函数仅一个,不能调用其他构造函数;普通构造函数可重载,且能调用同结构体的其他构造函数
- 值类型特性:Struct 赋值时拷贝完整数据,与 Class 的引用传递形成核心区别
- 可变控制:修改实例变量的方法需加
mut关键字,保证数据修改的可控性 - 封装特性:推荐使用属性设计器(Prop)替代 set/get 方法,结合
private修饰符强化数据安全 - 静态成员:静态变量 / 构造函数属于结构体本身,用于存储全局共享数据,静态构造函数仅初始化静态变量。
更多推荐
所有评论(0)