struct

SKILL.md

仓颉语言结构体 Skill

1. 结构体定义

1.1 基本语法

struct Rectangle {
    let width: Int64
    let height: Int64
    public init(width: Int64, height: Int64) {
        this.width = width
        this.height = height
    }
    public func area() { width * height }
}
  • 使用 struct 关键字 + 名称 + {} 体定义
  • 仅可在顶层作用域定义
  • 结构体体内可包含:成员变量、成员属性、静态初始化器、构造函数、成员函数

1.2 成员变量

  • 实例成员变量:通过结构体实例访问。可有初始值,也可无初始值(须有类型标注)
  • 静态成员变量:用 static 声明,通过结构体类型名访问(非实例)

1.3 静态初始化器

  • static init() — 无参数,不允许访问修饰符
  • 须初始化所有未初始化的静态成员变量
  • 每个结构体最多一个

1.4 构造函数

普通构造函数(init)

  • init(params) { ... }
  • 函数体初始化所有未初始化的实例成员变量
  • 使用 this 消除参数名与成员变量名的歧义
  • 多个 init 构造函数仅在构成有效重载时允许

主构造函数

  • 名称 = 结构体类型名。每个结构体最多一个
  • 参数可以是普通参数成员变量参数(前缀 let/var),后者同时定义成员变量和构造函数参数
struct Rectangle {
    public Rectangle(let width: Int64, let height: Int64) {}
}

自动生成的无参构造函数

  • 自定义构造函数(包括主构造函数)且所有实例成员变量有初始值时 → 编译器自动生成 public init()

1.5 成员函数

  • 实例成员函数:通过实例访问。可使用 this 访问实例成员变量。也可访问静态成员
  • 静态成员函数static func):通过类型名访问。不能访问实例成员或调用实例函数
  • 限制:同一个结构体中,静态方法和实例方法不能同名(即使参数不同)

1.6 成员属性(prop)

  • prop name: Type { get() { ... } } — 只读属性
  • mut prop name: Type { get() { ... } set(v) { ... } } — 读写属性
  • 实例属性通过实例访问,静态属性(static prop)通过类型名访问
  • 属性的详细规则参见 cangjie-class Skill 第 4 节

1.7 访问修饰符

修饰符 可见性
private 仅在结构体定义内
internal(默认) 当前包及子包
protected 当前模块
public 全局可见

1.8 禁止递归结构体

  • 直接和间接递归均不合法(编译错误):
struct R1 { let other: R1 }         // 错误:自引用
struct R2 { let other: R3 }         // 错误:相互引用
struct R3 { let other: R2 }

2. 创建结构体实例

2.1 创建

  • 通过结构体类型名调用构造函数:let r = Rectangle(10, 20)
  • 通过实例访问成员:r.widthr.area()

2.2 修改实例成员须满足两个条件

  1. 持有实例的变量须为 var(可变)
  2. 被修改的成员变量须声明为 var

2.3 值语义(赋值/传参时复制)

  • 赋值或传递结构体实例会创建副本(浅拷贝 — 引用类型成员仅复制引用)
  • 修改一个副本不影响另一个

3. mut 函数

3.1 问题

  • 由于结构体是值类型,普通实例成员函数不能修改实例的成员变量

3.2 解决方案

  • mut 函数 — 特殊的实例成员函数,可以原地修改结构体实例
struct Foo {
    var i = 0
    public mut func g() { i += 1 }  // 合法
}

3.3 mut 允许使用的位置

  • 仅在 interfacestruct 和结构体扩展中
  • 不能用于 class(类是引用类型,实例函数本身就能修改成员)

3.4 mut 不能修饰静态函数

public mut static func g(): Unit {} // 错误

3.5 mut 也可修饰运算符函数

public mut operator func +(rhs: A): A { A() }  // 合法

3.6 mut 函数中 this 的限制

  • this 不能被 Lambda 或嵌套函数捕获
  • this 不能作为表达式使用(如返回值)
  • 实例成员变量不能被 mut 函数内的 Lambda 捕获

3.7 接口中的 mut

  • 接口函数可声明为 mut
  • 结构体实现接口时须精确匹配 mut 修饰符(mut↔mut, 非mut↔非mut)
  • 实现接口时忽略 mut(直接使用普通 func
  • 将结构体实例赋给接口类型变量时会复制。通过接口变量调用 mut 函数修改的是副本,不影响原始结构体

3.8 mut 函数使用限制

规则 1:let 声明的结构体变量不能调用 mut 函数

let a = Foo()
a.f()    // 错误:a 是 let 声明的结构体
var b = Foo()
b.f()    // 正确:b 是 var
let c: I = Foo()
c.f()    // 正确:c 是接口类型,非结构体类型

规则 2:结构体类型变量上的 mut 函数不能作为一等公民使用

var a = Foo()
var fn = a.f    // 错误:不能将 mut 函数作为一等公民使用
var b: I = Foo()
fn = b.f        // 正确:b 是接口类型

规则 3:非 mut 实例成员函数不能调用 mut 函数;mut 函数可以调用非 mut 函数

struct Foo {
    var i = 0
    public mut func f(): Unit {
        i += 1
        g()     // 正确:mut 可调用非 mut
    }
    public func g(): Unit {
        f()     // 错误:非 mut 不能调用 mut
    }
}
Weekly Installs
3
First Seen
2 days ago
Installed on
opencode2
claude-code2
github-copilot2
codex2
kimi-cli2
gemini-cli2