1# Sendable使用规则与约束 2 3## Sendable class只能继承自Sendable class 4 5Sendable对象布局及原型链不可变,非Sendable对象可以通过特殊方式修改布局,不允许互相继承。这里的class不包括变量。Sendable class不能继承自变量。 6 7**正例:** 8 9```ts 10@Sendable 11class A { 12 constructor() { 13 } 14} 15 16@Sendable 17class B extends A { 18 constructor() { 19 super() 20 } 21} 22``` 23 24**反例:** 25 26```ts 27class A { 28 constructor() { 29 } 30} 31 32@Sendable 33class B extends A { 34 constructor() { 35 super() 36 } 37} 38``` 39 40 41## 非Sendable class只能继承自非Sendable class 42 43Sendable对象布局及原型链不可变,由于非Sendable对象可以通过特殊方式修改布局,因此不允许互相继承。 44 45**正例:** 46 47```ts 48class A { 49 constructor() { 50 } 51} 52 53class B extends A { 54 constructor() { 55 super() 56 } 57} 58``` 59 60**反例:** 61 62```ts 63@Sendable 64class A { 65 constructor() { 66 } 67} 68 69class B extends A { 70 constructor() { 71 super() 72 } 73} 74``` 75 76 77## 非Sendable class只能实现非Sendable interface 78 79如果非Sendable class实现了Sendable interface,可能会被认为是Sendable的,实际是非Sendable的,导致错误使用。 80 81**正例:** 82 83```ts 84interface I {}; 85 86class B implements I {}; 87``` 88 89**反例:** 90 91```ts 92import { lang } from '@kit.ArkTS'; 93 94type ISendable = lang.ISendable; 95 96interface I extends ISendable {}; 97 98class B implements I {}; 99``` 100 101 102## Sendable class/interface成员变量必须是Sendable支持的数据类型 103 104Sendable数据不能持有非Sendable数据,因此Sendable数据的成员属性必须为Sendable数据。 105 106**正例:** 107 108```ts 109@Sendable 110class A { 111 constructor() { 112 } 113 a: number = 0; 114} 115``` 116 117**反例:** 118 119```ts 120@Sendable 121class A { 122 constructor() { 123 } 124 b: Array<number> = [1, 2, 3] // 需使用collections.Array 125} 126``` 127 128 129## Sendable class/interface的成员变量不支持使用!断言 130 131Sendable对象的成员属性必须赋初值,“!”修饰的变量可以不赋初值,因此不支持使用“!” 。 132 133**正例:** 134 135```ts 136@Sendable 137class A { 138 constructor() { 139 } 140 a: number = 0; 141} 142``` 143 144**反例:** 145 146```ts 147@Sendable 148class A { 149 constructor() { 150 } 151 a!: number; 152} 153``` 154 155 156## Sendable class/interface的成员变量不支持使用计算属性名 157 158Sendable对象的布局不可变,计算属性不能静态确定对象布局,因此不支持。 159 160**正例:** 161 162```ts 163@Sendable 164class A { 165 num1: number = 1; 166 num2: number = 2; 167 add(): number { 168 return this.num1 + this.num2; 169 } 170} 171``` 172 173**反例:** 174 175```ts 176enum B { 177 b1 = "bbb" 178} 179@Sendable 180class A { 181 ["aaa"]: number = 1; // ["aaa"] is allowed in other classes in ets files 182 [B.b1]: number = 2; // [B.b1] is allowed in other classes in ets files 183} 184``` 185 186 187## 泛型类中的Sendable class,collections.Array,collections.Map,collections.Set的模板类型必须是Sendable类型 188 189Sendable数据不能持有非Sendable数据,因此泛型类中的Sendable数据的模版类型必须是Sendable类型。 190 191**正例:** 192 193```ts 194import { collections } from '@kit.ArkTS'; 195 196try { 197 let arr1: collections.Array<number> = new collections.Array<number>(); 198 let num: number = 1; 199 arr1.push(num); 200} catch (e) { 201 console.error(`taskpool execute: Code: ${e.code}, message: ${e.message}`); 202} 203``` 204 205**反例:** 206 207```ts 208import { collections } from '@kit.ArkTS'; 209 210try { 211 let arr1: collections.Array<Array<number>> = new collections.Array<Array<number>>(); 212 let arr2: Array<number> = new Array<number>(); 213 arr2.push(1); 214 arr1.push(arr2); 215} catch (e) { 216 console.error(`taskpool execute: Code: ${e.code}, message: ${e.message}`); 217} 218``` 219 220 221## Sendable class的内部不允许使用当前模块内上下文环境中定义的变量 222 223由于Sendable对象在不同并发实例间的上下文环境不同,属于单个虚拟机实例,如果直接访问会有非预期行为。不支持Sendable对象使用当前模块内上下文环境中定义的变量,如果违反,编译阶段会报错。 224 225> **说明:** 226> 227> 从API version 12开始,sendable class的内部支持使用top level的sendable class对象。 228 229**正例:** 230 231```ts 232import { lang } from '@kit.ArkTS'; 233 234type ISendable = lang.ISendable; 235 236interface I extends ISendable {} 237 238@Sendable 239class B implements I { 240 static o: number = 1; 241 static bar(): B { 242 return new B(); 243 } 244} 245 246@Sendable 247class C { 248 v: I = new B(); 249 u: number = B.o; 250 251 foo() { 252 return B.bar(); 253 } 254} 255``` 256 257**反例:** 258 259```ts 260import { lang } from '@kit.ArkTS'; 261 262type ISendable = lang.ISendable; 263 264interface I extends ISendable {} 265 266@Sendable 267class B implements I {} 268 269function bar(): B { 270 return new B(); 271} 272 273let b = new B(); 274 275{ 276 @Sendable 277 class A implements I {} 278 279 @Sendable 280 class C { 281 u: I = bar(); // bar不是sendable class对象,编译报错 282 v: I = new A(); // A不是定义在top level中,编译报错 283 284 foo() { 285 return b; // b不是sendable class对象,而是sendable class的实例,编译报错 286 } 287 } 288} 289``` 290 291 292## Sendable class和Sendable function不能使用除了\@Sendable的其它装饰器 293 294如果类装饰器定义在ts文件中,产生修改类的布局的行为,那么会造成运行时的错误。 295 296**正例:** 297 298```ts 299@Sendable 300class A { 301 num: number = 1; 302} 303``` 304 305**反例:** 306 307```ts 308@Sendable 309@Observed 310class C { 311 num: number = 1; 312} 313``` 314 315 316## 不能使用对象字面量/数组字面量初始化Sendable类型 317 318对象字面量/数组字面量是非Sendable类型,Sendable数据类型只能通过Sendable类型的new表达式创建。 319 320**正例:** 321 322```ts 323import { collections } from '@kit.ArkTS'; 324 325let arr1: collections.Array<number> = new collections.Array<number>(1, 2, 3); // 是Sendable类型 326``` 327 328**反例:** 329 330```ts 331import { collections } from '@kit.ArkTS'; 332 333let arr2: collections.Array<number> = [1, 2, 3]; // 不是Sendable类型,编译报错 334let arr3: number[] = [1, 2, 3]; // 不是Sendable类型,正例,不报错 335let arr4: number[] = new collections.Array<number>(1, 2, 3); // 编译报错 336``` 337 338 339## 非Sendable类型不可以as成Sendable类型 340 341除了Object类型,非Sendable类型不可以as成Sendable类型。非Sendable类型通过as强转成Sendable类型后实际是非Sendable的类型数据,会导致错误使用。Sendable类型在不违反Sendable规则的前提下需要和非Sendable类型行为兼容,因此Sendable类型可以as成非Sendable类型。 342 343**正例:** 344 345```ts 346class A { 347 state: number = 0; 348} 349 350@Sendable 351class SendableA { 352 state: number = 0; 353} 354 355let a1: A = new SendableA() as A; 356``` 357 358**反例:** 359 360```ts 361class A { 362 state: number = 0; 363} 364 365@Sendable 366class SendableA { 367 state: number = 0; 368} 369 370let a2: SendableA = new A() as SendableA; 371``` 372 373 374## 箭头函数不支持共享 375 376箭头函数不支持使用Sendable装饰器,是非Sendable函数,因此不支持共享。 377 378**正例:** 379 380```ts 381@Sendable 382type SendableFuncType = () => void; 383 384@Sendable 385function SendableFunc() { 386 console.info("Sendable func"); 387} 388 389@Sendable 390class SendableClass { 391 constructor(f: SendableFuncType) { 392 this.func = f; 393 } 394 func: SendableFuncType; 395} 396 397let sendableClass = new SendableClass(SendableFunc); 398``` 399 400**反例:** 401 402```ts 403@Sendable 404type SendableFuncType = () => void; 405let func: SendableFuncType = () => {}; // 编译报错 406 407@Sendable 408class SendableClass { 409 func: SendableFuncType = () => {}; // 编译报错 410} 411``` 412 413 414## Sendable装饰器修饰类型时仅支持修饰函数类型 415 416当前仅支持声明Sendable函数类型,因此只能修饰函数类型。 417 418**正例:** 419 420```ts 421@Sendable 422type SendableFuncType = () => void; 423``` 424 425**反例:** 426 427```ts 428@Sendable 429type A = number; // 编译报错 430 431@Sendable 432class C {} 433 434@Sendable 435type D = C; // 编译报错 436``` 437 438 439## 注意事项 440 441 442在HAR中使用Sendable时,需开启编译生成TS文件的配置。详情可查[编译生成TS文件](../quick-start/har-package.md#编译生成ts文件)。 443 444 445## 与TS/JS交互的规则 446 447 448### ArkTS通用规则(目前只针对Sendable对象) 449 450| 规则 | 451| -------- | 452| Sendable对象传入TS/JS的接口中,禁止操作其对象布局(增、删属性,改变属性类型)。 | 453| Sendable对象设置到TS/JS的对象上,TS中获取到这个Sendable对象后,禁止操作其对象布局(增、删属性,改变属性类型)。 | 454| Sendable对象放入TS/JS的容器中,TS中获取到这个Sendable对象后,禁止操作其对象布局(增、删属性,改变属性类型)。 | 455 456> **说明:** 457> 458> 此处改变属性类型不包括Sendable对象类型的改变,比如从Sendable class A 变为Sendable class B。 459 460 461### NAPI规则(目前只针对Sendable对象) 462 463| 规则 | 464| -------- | 465| 禁止删除属性,不能使用的接口有:napi_delete_property。 | 466| 禁止新增属性,不能使用的接口有:napi_set_property、napi_set_named_property、napi_define_properties。 | 467| 禁止修改属性类型,不能使用的接口有:napi_set_property、napi_set_named_property、napi_define_properties。 | 468| 不支持Symbol相关接口和类型,不能使用的接口有:napi_create_symbol、napi_is_symbol_object、napi_symbol。 | 469 470 471## 与UI交互的规则 472 473Sendable数据需要与[makeObserved](../quick-start/arkts-new-makeObserved.md)联用,才可以观察Sendable对象的数据变化,具体使用请参考[makeObserved和@Sendable装饰的class配合文档](../quick-start/arkts-new-makeObserved.md#makeobserved和sendable装饰的class配合使用)。 474