文档编程语言【免费下载链接】cangjie_docs仓颉编程语言开发者文档。项目地址https://gitcode.com/Cangjie/cangjie_docs点击查看免费下载属性Properties是仓颉语言中用于间接获取和设置值的语言机制它通过一个 getter 和可选的 setter 对外暴露数据访问接口而调用方使用属性时与使用普通变量无异。本文以仓颉开发者文档 prop.md 为骨架系统讲解属性的定义语法、getter/setter 函数类型语义、mut修饰规则、修饰符体系、抽象属性与覆盖/重定义规则并结合class、struct、enum、扩展与反射等仓库文档给出可直接编译运行的完整示例。读完本文你将能够熟练地在类、接口、结构体、枚举与扩展中定义属性设计出兼具封装性与可读性的数据访问接口。属性是什么用 getter/setter 封装数据访问属性提供了一个 getter 和一个可选的 setter用来间接获取和设置值。使用属性的时候与普通变量无异——你只需要对数据操作对内部的实现无感知。这种间接性带来了四个典型收益访问控制、数据监控、跟踪调试、数据绑定。例如可以在 getter/setter 中插入日志、校验、缓存或通知逻辑而调用方无需感知这些内部细节。属性在使用时可以作为表达式触发 getter或被赋值触发 setter。文档以类和接口为例进行说明但属性不仅限于类和接口还可在struct、enum、extend中定义。下面是一个最典型的属性示例b封装了外部对私有成员a的访问。class Foo { private var a 0 public mut prop b: Int64 { get() { println(get) a } set(value) { println(set) a value } } } main() { var x Foo() let y x.b 1 // get x.b y // set }这里Foo提供了一个名为b的属性针对 getter/setter 两个功能仓颉提供了get和set两种语法来定义当一个类型为Foo的变量x访问b时会调用b的 get 操作返回类型为Int64的值因此可以与1相加当x对b赋值时会调用b的 set 操作将y的值传给 set 的形参value最终将value赋值给a。通过属性b外部对Foo的成员变量a完全不感知却可以通过b做到同样的访问和修改操作实现了有效的封装性。程序输出如下get set属性的定义与语法结构属性可以在interface、class、struct、enum、extend中定义。一个典型的属性语法结构如下class Foo { public prop a: Int64 { get() { 0 } } public mut prop b: Int64 { get() { 0 } set(v) {} } }其中使用prop声明的a和b都是属性类型都是Int64。这里可以提炼出两条强制规则a是无mut修饰符的属性这类属性有且仅有定义 getter对应取值实现b是使用mut修饰的属性这类属性必须分别定义 getter对应取值和 setter对应赋值的实现。注意对于数值、元组、函数、Bool、Unit、Nothing、String、Range和enum类型在它们的扩展和声明中不能声明mut修饰的属性也不能实现带mut属性的接口。也就是说上述这些类型只能承载只读属性。从关键字表见 keyword.md可以看到prop是仓颉的保留关键字不能作为标识符使用属性的声明统一由它引出。getter 与 setter 的函数类型语义属性的 getter 和 setter 分别对应两个不同的函数二者的函数类型是固定的getter 函数类型是() - T其中T是该属性的类型。当使用该属性作为表达式时会执行 getter 函数setter 函数类型是(T) - Unit其中T是该属性的类型形参名需要显式指定。当对该属性赋值时会执行 setter 函数setter 中的形参对应赋值时传入的值。getter 和 setter 的实现中可以像函数体一样包含声明和表达式与函数体的规则一致函数体规则详见 define_functions.md#函数体函数体通常包含变量定义和表达式其类型为最后一项的类型若最后一项为表达式函数体类型即该表达式的类型若最后一项为变量定义或函数声明或函数体为空则类型为Unit。因此getter 的末尾直接写表达式即为其返回值。下面这个示例展示了 setter 形参v如何承接赋值传入的值class Foo { private var j 0 public mut prop i: Int64 { get() { j } set(v) { j v } } }需要注意一个陷阱在属性的 getter 和 setter 中访问属性自身属于递归调用与函数调用一样可能会出现死循环。例如在b的 getter 中写b而不是a会不断触发 getter 自身导致无限递归。正确的做法是在 getter/setter 内部访问真正承载数据的成员变量。属性修饰符访问控制、静态属性与继承覆盖可以在prop前面声明需要的修饰符。属性支持访问修饰符如public、private也支持static、open、override、redef等。访问修饰符和成员函数一样属性可以用public、private等访问修饰符控制可见性class Foo { public prop a: Int64 { get() { 0 } } private prop b: Int64 { get() { 0 } } }open / override / redef在子类型中覆盖与重定义和成员函数一样成员属性也支持open、override、redef修饰因此可以在子类型中覆盖/重定义父类型属性的实现。覆盖规则有一条硬性约束子类型覆盖父类型的属性时如果父类型属性带有mut修饰符则子类型属性也需要带有mut修饰符同时也必须保持一样的类型。如下代码所示A中定义了x和y两个属性B中可以分别对x和y进行override/redefstatic属性使用redef实例属性使用overrideopen class A { private var valueX 0 private static var valueY 0 public open prop x: Int64 { get() { valueX } } public static mut prop y: Int64 { get() { valueY } set(v) { valueY v } } } class B : A { private var valueX2 0 private static var valueY2 0 public override prop x: Int64 { get() { valueX2 } } public static redef mut prop y: Int64 { get() { valueY2 } set(v) { valueY2 v } } }注意父类A需要open修饰才可被继承父类中需要被覆盖的属性用open标记子类中实例属性用override静态属性用redef且mut一致性、类型一致性都必须保持。静态属性属性还分为实例成员属性和静态成员属性。静态属性使用static修饰通过类型名访问其定义、使用规则与class的静态成员变量一致成员变量规则详见 class.md#class-成员变量。抽象属性接口与抽象类的数据操作约定类似于抽象函数在interface和抽象类中也可以声明抽象属性——这些抽象属性没有实现只保留签名interface I { prop a: Int64 } abstract class C { public prop a: Int64 }当实现类型实现interface或者非抽象子类继承抽象类时必须实现这些抽象属性。与覆盖的规则一样如果父类型属性带有mut修饰符则实现类型或子类的属性也需要带有mut修饰符并保持一样的类型interface I { prop a: Int64 mut prop b: Int64 } class C : I { private var value 0 public prop a: Int64 { get() { value } } public mut prop b: Int64 { get() { value } set(v) { value v } } }抽象属性让接口和抽象类对一些数据操作能以更加易用的方式进行约定相比函数的方式更直观。下面是对同一个size值的获取和设置进行约定时属性方式I1与函数方式I2的对比——属性方式代码更少也更符合对数据操作的意图interface I1 { mut prop size: Int64 } interface I2 { func getSize(): Int64 func setSize(value: Int64): Unit } class C : I1 I2 { private var mySize 0 public mut prop size: Int64 { get() { mySize } set(value) { mySize value } } public func getSize() { mySize } public func setSize(value: Int64) { mySize value } } main() { let a: I1 C() a.size 5 println(a.size) let b: I2 C() b.setSize(5) println(b.getSize()) }5 5同样的语义属性方式a.size 5/println(a.size)比函数方式b.setSize(5)/println(b.getSize())更贴近对数据进行操作的意图同时代码量更少。属性的使用实例属性、静态属性与 let/var 语义属性分为实例成员属性和静态成员属性。成员属性的使用方式和成员变量的使用方式一样实例属性通过对象访问静态属性通过类型名访问成员变量访问规则详见 class.md#class-成员变量class A { public prop x: Int64 { get() { 123 } } public static prop y: Int64 { get() { 321 } } } main() { var a A() println(a.x) // 123 println(A.y) // 321 }结果为123 321属性与变量的赋值语义还有以下对应关系无mut修饰符的属性类似let声明的变量不能被赋值。下面的代码中读取x.i合法但x.i 1会编译报错class A { private let value 0 public prop i: Int64 { get() { value } } } main() { var x A() println(x.i) // OK x.i 1 // Error }带有mut修饰符的属性类似var声明的变量可以取值也可以被赋值class A { private var value: Int64 0 public mut prop i: Int64 { get() { value } set(v) { value v } } } main() { var x A() println(x.i) // OK x.i 1 // OK }0属性的更多落地场景扩展、结构体、枚举与反射属性在仓颉各类型体系中均可使用以下场景可以帮你把属性用到更广阔的地方1. 扩展中定义属性extend。扩展可以为当前package中可见的类型除函数、元组、接口添加成员属性适合在不破坏被扩展类型封装性的前提下补充数据访问能力详见 extend_overview.md。例如extend Boo { public prop x: Int64 { // 添加成员属性 get() { 123 } } }不过扩展受限较多扩展不能增加成员变量、扩展的属性和函数必须拥有实现、扩展的属性不能用open/override/redef修饰也不能访问被扩展类型中private修饰的成员。2. struct 与 enum 中的属性。struct的定义体中可声明成员变量、成员属性等详见 define_struct.mdenum体中同样可以定义成员属性但要求构造器、成员函数、成员属性之间不能重名详见 enum.md。3. 通过反射检查与修改属性。仓颉的反射机制支持对属性进行检查与修改TypeInfo的子类ClassTypeInfo提供接口访问类公开的成员变量、属性与函数instanceProperties可列出实例成员属性getInstanceProperty获取属性信息isMutable判断属性是否可写详见 dynamic_feature.md。例如反射输出的属性描述形式为[prop p1: Int64, mut prop p2: Int64]其中mut前缀即标识可写属性——这与编译期属性声明的mut语义完全一致。4. 跨平台common/specific场景中的属性限制。在多平台开发中common属性可以有具体实现也可以仅保留属性签名交由specific属性实现若common属性有完整实现则可省略specific属性common与specific属性的类型、可见性和可赋值性必须相同common/specific的interface属性中若common属性包含具体实现则specific属性必须也包含具体实现详见 common_platform.md。小结仓颉的属性机制围绕prop关键字展开核心要点可以归纳为维度规则要点定义位置interface、class、struct、enum、extendgetter函数类型() - T属性作表达式时执行无mut属性必须且只能定义 gettersetter函数类型(T) - Unit形参名需显式指定mut属性必须同时定义 getter 与 settermut限制数值、元组、函数、Bool、Unit、Nothing、String、Range、enum类型不能声明/实现mut属性修饰符public/private等访问修饰、static、open/override/redef覆盖时mut与类型必须一致抽象属性在interface与抽象类中声明实现类型/非抽象子类必须实现使用语义无mut属性 ≈let变量只读mut属性 ≈var变量可读可写递归陷阱在 getter/setter 中访问属性自身会递归调用可能导致死循环属性把数据访问从具体存储中解放出来让访问控制、数据监控、跟踪调试与数据绑定有了自然的实现位置是仓颉面向对象编程中兼具封装性与表达力的核心语言特性。赞分享文档编程语言【免费下载链接】cangjie_docs仓颉编程语言开发者文档。项目地址https://gitcode.com/Cangjie/cangjie_docs点击查看免费下载相关推荐wasm-bindgen 属性指南用 getter 与 setter 在 Rust 中定义 JavaScript 类属性wasm bindgen 属性指南用 getter 与 setter 在 Rust 中定义 JavaScript 类属性 本文是 wasm bindgen 属开发工具htmx hx-disinherit 属性完全指南精确控制属性继承与局部覆盖htmx hx disinherit 属性完全指南精确控制属性继承与局部覆盖 htmx 默认会把父元素上的许多属性自动继承给子元素例如在父节点设置 hx前端Web框架Yii 2 属性机制完全指南基于 getter/setter 的魔术属性定义与源码原理Yii 2 属性机制完全指南基于 getter/setter 的魔术属性定义与源码原理 本指南以 Yii 2 框架文档《プロパティ》docs/guide j后端Web框架上一篇颠覆式缠论可视化通达信Indicator插件革新技术分析范式下一篇轻量级高效解决方案JPEGView的图像查看与编辑全功能工具创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考