• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# 示例代码风格
2本规范适用于文档中ArkTS、JavaScript和C/C++等编程语言的示例代码片段,旨在提高OpenHarmony文档示例代码的可读性、可维护性,以及风格一致性。
3
4## 代码规范
5
6### 【规则】遵守基本编程规范
7
8【描述】
9
10文档的示例代码需要遵循[JavaScript语言编程规范](../OpenHarmony-JavaScript-coding-style-guide.md)、[C语言编程规范](../OpenHarmony-c-coding-style-guide.md)和[C++语言编程规范](../OpenHarmony-cpp-coding-style-guide.md)基本的编码规范,包括命名规范、代码格式和代码规范等。
11
12### 【规则】每个接口(包括方法和组件)均需要提供示例代码
13
14【描述】
15
16API参考中,每个接口(包括方法和组件)均需要提供示例代码。如果多个API存在关联关系,则需要在一个场景化的代码示例中体现。
17
18### 【规则】每个接口提供的示例代码中无须增加`try...catch...`
19
20【描述】
21
22在接口示例代码中,为了保持示例代码的简洁性和易读性,不需要为每个接口调用添加`try...catch...`语句来捕获异常。
23
24示例代码主要用于演示如何正确地使用接口,并提供了正确的处理方式。添加异常处理代码可能会使示例代码变得冗长且难以理解。
25
26【正例】
27
28```ts
29// 正例1:
30let want = {
31  bundleName: 'com.example.myapplication',
32  abilityName: 'EntryAbility'
33};
34
35this.context.startAbility(want)
36  .then(() => {
37    // 执行正常业务
38    console.info('Succeeded in starting ability.');
39  })
40  .catch((err) => {
41    // 处理业务逻辑错误
42    console.error(`Failed to start ability. Code is ${err.code}, message is ${err.message}`);
43  });
44
45// 正例2:
46let pathDir = ...; // 应用文件路径
47let filePath = pathDir + '/test.txt';
48let str = fs.readTextSync(filePath, { offset: 1, length: 3 });
49console.info(`Succeed in reading text, str is ${str}`);
50```
51
52【反例】
53
54```ts
55// 反例1:
56let want = {
57  bundleName: 'com.example.myapplication',
58  abilityName: 'EntryAbility'
59};
60
61try {
62  this.context.startAbility(want)
63    .then(() => {
64      // 执行正常业务
65      console.info('Succeeded in starting ability.');
66    })
67    .catch((err) => {
68      // 处理业务逻辑错误
69      console.error(`Failed to start ability. Code is ${err.code}, message is ${err.message}`);
70    });
71} catch (err) {
72  // 处理入参错误异常
73  console.error(`Failed to start ability. Code is ${err.code}, message is ${err.message}`);
74}
75
76// 反例2:
77let pathDir = ...; // 应用文件路径
78let filePath = pathDir + '/test.txt';
79try {
80  let str = fs.readTextSync(filePath, { offset: 1, length: 3 });
81  console.info(`Succeed in reading text, str is ${str}`);
82} catch (err) {
83  console.error(`Failed to read text. Code is ${err.code}, message is ${err.message}`);
84}
85```
86
87### 【规则】示例代码中的变量需要包含定义、使用方法或者来源链接参考或者说明
88
89【描述】
90
91示例代码中的变量需要包含定义、使用方法或者来源链接参考或者说明,以确保开发者能够理解如何使用。例如,如果涉及到应用开发路径,需要提供获取应用开发路径的链接参考或方法。
92
93【正例】
94
95示例中的context的获取方式请参见[获取UIAbility的上下文信息](../../application-dev/application-models/uiability-usage.md#获取uiability的上下文信息)。
96
97```ts
98let context = ...; // UIAbilityContext
99let want = {
100  deviceId: '', // deviceId为空表示本设备
101  bundleName: 'com.example.myapplication',
102  abilityName: 'FuncAbility',
103  moduleName: 'func', // moduleName非必选
104  parameters: { // 自定义信息
105    info: '来自EntryAbility Index页面',
106  },
107}
108// context为调用方UIAbility的UIAbilityContext
109context.startAbilityForResult(want).then((data) => {
110  ...
111}).catch((err) => {
112  console.error(`Failed to start ability for result. Code is ${err.code}, message is ${err.message}`);
113})
114```
115
116【反例】
117
118```ts
119// 反例1:使用到的context和want变量未进行定义
120// context为调用方UIAbility的UIAbilityContext
121context.startAbilityForResult(want).then((data) => {
122  ...
123}).catch((err) => {
124  console.error(`Failed to start ability for result. Code is ${err.code}, message is ${err.message}`);
125})
126
127// 反例2:UIAbilityContext的使用来源不止this.context这一种,这里列举出来就会有展示不全的问题
128let context = this.context; // UIAbilityContext
129let want = {
130  deviceId: '', // deviceId为空表示本设备
131  bundleName: 'com.example.myapplication',
132  abilityName: 'FuncAbility',
133  moduleName: 'func', // moduleName非必选
134  parameters: { // 自定义信息
135    info: '来自EntryAbility Index页面',
136  },
137}
138// context为调用方UIAbility的UIAbilityContext
139context.startAbilityForResult(want).then((data) => {
140  ...
141}).catch((err) => {
142  console.error(`Failed to start ability for result. Code is ${err.code}, message is ${err.message}`);
143})
144```
145
146### 【建议】一致的依赖包命名风格
147
148【描述】
149
150导入的依赖包的命名与其依赖包的命名空间保持一致,以便于维护和理解代码。
151
152采用一致的依赖包命名风格还可以方便IDE进行提示导入,提高编码效率。
153
154【正例】
155
156```ts
157import promptAction from '@ohos.promptAction';
158```
159
160【反例】
161
162```ts
163// 包名和其命名空间不一致,不利于维护和理解代码
164import prompt from '@ohos.promptAction';
165```
166
167### 【规则】组件宽高等属性不加单位
168
169【描述】
170
171为了保持代码的一致性和简洁性,在设置组件的宽度、高度等属性时,应该尽量避免添加单位,因为组件的宽度、高度等属性默认以像素为单位。同时,避免添加单位也可以提高代码的可读性和便于维护。
172
173【正例】
174
175```ts
176Image('test.png')
177  .width(100)
178  .height(100)
179
180Text('Hello World')
181  .fontSize(50)
182```
183
184【反例】
185
186```ts
187Image('test.png')
188  .width('100vp')
189  .height('100vp')
190
191Text('Hello World')
192  .fontSize('50fp')
193```
194
195## 代码展示
196
197### 【规则】行内代码使用`包裹显示
198
199【描述】
200
201正文描述中涉及代码的内容,比如实际代码中的方法名、参数名或代码文件名等,使用`包裹显示。
202
203【正例】
204
205在`Index.ets`文件中实现页面跳转。
206
207【反例】
208
209Index.ets文件中实现页面跳转。
210
211### 【规则】代码示例、命令行使用代码样式进行代码染色
212
213【描述】
214
215对代码示例、命令行使用代码样式。在Markdown中,使用```呈现代码样式,同时指定语言类型。
216
217代码染色是指在编辑器中对代码进行不同颜色的标记,以区分不同语法元素的功能。例如在编辑器中对不同的关键字、变量名、注释等使用不同的颜色进行标记,可以让代码更加易读易懂。
218
219![代码块示例](figures/code-block-example.png)
220
221### 【规则】代码格式化
222
223【描述】
224
225在将代码示例放入指南之前,使用DevEco Studio中的代码格式化功能对代码进行格式化,以确保代码的一致性和可读性。
226
227格式化代码的方法包括缩进、空格、换行等,这些方法可以使代码更易于阅读和理解,提高代码的可维护性和扩展性。
228
229【正例】
230
231```ts
232import UIAbility from '@ohos.app.ability.UIAbility';
233import window from '@ohos.window';
234
235export default class EntryAbility extends UIAbility {
236  onWindowStageCreate(windowStage: window.WindowStage) {
237    windowStage.loadContent('pages/Index', (err, data) => {
238    });
239  }
240}
241```
242
243【反例】
244
245```ts
246import UIAbility from '@ohos.app.ability.UIAbility';
247import window from '@ohos.window';
248
249export default class EntryAbility extends UIAbility {
250  onWindowStageCreate(windowStage: window.WindowStage) {
251  // 代码未格式化,没有缩进
252  windowStage.loadContent('pages/Index', (err, data) => {
253  });
254  }
255}
256```
257
258### 【规则】省略代码展示
259
260【描述】
261
262当需要在文档或代码中展示省略的部分时,使用统一的省略代码格式。省略代码应该简洁明了,避免冗长或混乱的格式。
263
264【正例】
265
266```ts
267// 正例1:
268...
269
270// 正例2:
271// To do sthing.
272```
273
274【反例】
275
276```ts
277// 反例1:
278// ...
279
280// 反例2:
281....
282
283// 反例3:
284......
285```
286
287### 【规则】代码注释展示
288
289【描述】
290
291示例代码中的关键内容和逻辑需要添加注释来说明,以确保开发者理解代码的作用。
292
293适时为代码块添加注释,特别是有解释说明、开发建议或注意事项的位置。恰当的注释可有效提升代码块可读性,帮助开发者快速掌握开发过程。
294
295注释符与代码块语法保持一致,禁止自创注释符。注释符与注释内容间统一添加一个空格。例如:对于ArkTS代码块,注释写法为“// 注释内容”。
296
297当一行注释内容过长时,注意断句切分到下一行呈现。
298
299代码注释应该清晰、简洁、有用,能够方便别人理解代码的含义和作用。注释应该写在代码上方或右方。
300
301【正例】
302
303```ts
304// 正例1:
305// 定义生命周期回调对象
306let abilityLifecycleCallback = {};
307
308// 正例2:
309let abilityLifecycleCallback = {}; // 定义生命周期回调对象
310```
311
312【反例】
313
314```ts
315// 反例1:注释符与注释内容之间没有添加空格
316//定义生命周期回调对象
317let abilityLifecycleCallback = {};
318
319// 反例2:注释符与注释内容之间没有添加空格
320let abilityLifecycleCallback = {}; //定义生命周期回调对象
321
322// 反例3:注释符与注释内容之间添加了多个空格
323let abilityLifecycleCallback = {};       // 定义生命周期回调对象
324```
325
326## 异常处理
327
328### 【规则】在可能出现异常的代码段加上异常捕获,并按不同的异常类型进行分支判断
329
330【描述】
331
332在可能出现异常的代码段加上异常捕获,并按不同的异常类型进行分支判断,针对不同的异常类型需要使用统一的异常分支判断方式。
333
334【正例】
335
336```ts
337// 情形1:err为undefined的场景
338if (err) {
339  ...
340}
341
342// 情形2:err.code为非0的场景
343if (err.code) {
344  ...
345}
346```
347
348【反例】
349
350```ts
351// 反例1:
352if (err == null) {
353  ...
354}
355
356// 反例2:
357if (err != null) {
358  ...
359}
360
361// 反例3:
362if (err == undefined) {
363  ...
364}
365
366// 反例4:
367if (err === undefined) {
368  ...
369}
370
371// 反例5:
372if (err !== undefined) {
373  ...
374}
375```
376
377### 【规则】使用console.error输出异常的详细信息,包含错误码和相关的message信息
378
379【描述】
380
381当存在异常情况时,统一使用`console.error(...)`方法将异常信息打印到控制台,以便在调试时能够快速发现问题。
382
383在异常处理中,应该打印出异常的详细信息以便调试。
384
385在打印异常信息时,应该使用模板字符串,并标明异常信息的`code`和`message`参数。
386
387【正例】
388
389```ts
390// 模板:
391console.error(`Failed to do sthing. Code: ${err.code}, message: ${err.message}`);
392
393// 正例:
394notificationManager.publish(notificationRequest, (err) => {
395  if (err) {
396    // 异常分支打印
397    console.error(`Failed to publish notification. Code: ${err.code}, message: ${err.message}`);
398    return;
399  }
400  ...
401});
402```
403
404【反例】
405
406```ts
407// 反例1:错误日志使用console.log输出,不足以让开发者在调试时快速找到问题
408notificationManager.publish(notificationRequest, (err) => {
409  if (err) {
410    // 异常分支打印
411    console.log(`Failed to publish notification. Code: ${err.code}, message: ${err.message}`);
412    return;
413  }
414  ...
415});
416
417// 反例2:错误日志使用console.info输出,而非console.error,不利于开发者区分日志级别,快速找到问题
418notificationManager.publish(notificationRequest, (err) => {
419  if (err) {
420    // 异常分支打印
421    console.info(`Failed to publish notification. Code: ${err.code}, message: ${err.message}`);
422    return;
423  }
424  ...
425});
426
427// 反例3:异常信息缺乏具体的code和message参数,不利于开发者定位和解决问题
428console.error(`Failed to publish notification, err: ${err}`);
429
430// 反例4:使用单引号而非模板字符串的双引号,导致变量无法解析,输出的日志信息不正确
431console.error('Failed to publish notification, err: ${err}');
432
433// 反例5:使用字符串拼接和JSON序列化输出错误信息,不够直观和简洁,会增加日志产生量,不利于快速定位问题
434console.error('Failed to publish notification, err: ' + JSON.stringify(err));
435```
436
437## 日志打印
438
439### 【规则】正常日志打印使用console.info,以提供程序运行的状态和关键信息
440
441【描述】
442
443在代码编写过程中,为了更好地记录程序运行过程中的信息,开发者需要使用日志打印,以便于在程序出现异常时进行定位和排查。
444
445在正常情况下,使用`console.info(...)`来打印正常日志信息。
446
447【正例】
448
449```ts
450// 模板:
451console.info('Succeeded in doing sthing.');
452
453// 正例:
454notificationManager.publish(notificationRequest, (err) => {
455  if (err) {
456    ...
457    return;
458  }
459  console.info('Succeeded in publishing notification.');
460});
461```
462
463【反例】
464
465```ts
466// 反例1:使用console.log(...)可能会让程序员产生困惑,无法明确该日志信息是正常日志还是错误日志
467notificationManager.publish(notificationRequest, (err) => {
468  if (err) {
469    ...
470    return;
471  }
472  console.log('Succeeded in publishing notification.');
473});
474
475// 反例2:使用了console.error(...)而不是console.info(...)来打印正常日志信息。console.error通常用于打印错误信息,而不是正常的日志信息
476notificationManager.publish(notificationRequest, (err) => {
477  if (err) {
478    ...
479    return;
480  }
481  console.error('Succeeded in publishing notification.');
482});
483```
484
485### 【规则】正常成功日志打印使用succeeded,以表示程序执行成功的结果
486
487【描述】
488
489在日志打印中使用一致的语言,例如成功日志可以使用`succeeded`来表达。
490
491【正例】
492
493```ts
494// 模板:
495console.info('Succeeded in doing sthing.');
496
497// 正例:
498notificationManager.publish(notificationRequest, (err) => {
499  if (err) {
500    ...
501    return;
502  }
503  console.info('Succeeded in publishing.');
504});
505```
506
507【反例】
508
509```ts
510// 反例1:
511notificationManager.publish(notificationRequest, (err) => {
512  if (err) {
513    ...
514    return;
515  }
516  console.info('Invoke publish success.');
517});
518
519// 反例2:
520notificationManager.publish(notificationRequest, (err) => {
521  if (err) {
522    ...
523    return;
524  }
525  console.info('Invoke publish successful.');
526});
527
528// 反例3:
529notificationManager.publish(notificationRequest, (err) => {
530  if (err) {
531    ...
532    return;
533  }
534  console.info('Invoke publish successfully.');
535});
536```
537
538## 代码逻辑
539
540### 【规则】回调方法中使用箭头函数替代常规函数
541
542【描述】
543
544在使用回调方法时,应该尽可能使用箭头方法代替常规方法,箭头方法的一个主要优点是可以避免 `this` 指向问题。在箭头方法中,`this` 绑定的是它所处的上下文的 `this` 值,而不是方法被调用时的 `this` 值。这样可以避免在使用常规方法时需要使用 `bind()` 或 `call()` 来绑定 `this` 的问题,从而简化代码并提高可读性。
545
546【正例】
547
548```ts
549notificationManager.publish(notificationRequest, (err) => {
550  if (err) {
551    ...
552    return;
553  }
554  console.info('Succeeded in publishing notification.');
555});
556```
557
558【反例】
559
560```ts
561notificationManager.publish(notificationRequest, function (err) {
562  if (err) {
563    ...
564    return;
565  }
566  console.info('Succeeded in publishing notification.');
567});
568```
569
570### 【规则】禁止使用废弃接口
571
572【描述】
573
574禁止使用废弃接口,因为他们可能会在未来的版本中被删除或更改。使用最新的接口可以确保代码的稳定性和可维护性。
575
576使用废弃接口可能导致代码不稳定,也可能会因为该接口在后续版本的更新中被废弃而引发编译错误、运行错误等问题。
577
578如果在后续的版本中废除了某些接口,所有依赖这些接口的示例代码都需要同步适配修改。
579
580【正例】
581
582```ts
583import fs from '@ohos.file.fs';
584
585function createFile() {
586  // 获取应用文件路径
587  let context = ...; // UIAbilityContext
588  let filesDir = context.filesDir;
589
590  // 新建并打开文件
591  let file = fs.openSync(filesDir + '/test.txt', fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
592  // 写入一段内容至文件
593  let writeLen = fs.writeSync(file.fd, 'Try to write str.');
594  // 从文件读取一段内容
595  let buf = new ArrayBuffer(1024);
596  let readLen = fs.readSync(file.fd, buf, { offset: 0 });
597  // 关闭文件
598  fs.closeSync(file);
599}
600```
601
602【反例】
603
604```ts
605// 使用了废弃的fileio接口,而不是推荐的fs接口
606import fileio from '@ohos.fileio';
607
608function createFile() {
609  // 获取应用文件路径
610  let context = ...; // UIAbilityContext
611  let filesDir = context.filesDir;
612
613  // 新建并打开文件
614  let fileFD = fileio.openSync(filesDir + '/test.txt', 0o102, 0o640);
615  // 写入一段内容至文件
616  let writeLen = fileio.writeSync(fileFD, 'Try to write str.');
617  // 从文件读取一段内容
618  let buf = new ArrayBuffer(1024);
619  let readLen = fileio.readSync(fileFD, buf, { offset: 0 });
620  // 关闭文件
621  fileio.closeSync(fileFD);
622}
623```