科研小技巧——MATLAB的编码风格

引言

MATLAB是我们在科研工作常用的一种语言,虽然最近有说MATLAB开始禁止一部分中国高校对其的使用,将来国产软件也会逐步赶上,但是目前来说,MATLAB还是值得我们进一步学习的。
这一篇文章介绍了MATLAB代码的编写规范,可以帮助我们写出更好的,更可读的代码。
毕竟有这么一句话:Any fool can write code that a computer can understand. Good programmers write code that humans can understand。
任何一个傻子都能写出可以运行的代码,但只有高手才能写出别人能看懂的代码。
拿出你的工匠精神,一起开始学习MATLAB的编码规范吧

1 命名规则

1.1 变量

  • 变量名应该采用驼峰命名法,并且以小写字母开头,尽量不要使用下划线分割名词的方式来定义变量
  • 大范围使用的变量一定要有有意义的变量名,小范围使用的变量可以用短名称
    • 通常短名称里面:i,j,k,m,n代表整数,x,y,z代表小数
  • 以n开头的变量,通常用来表示,代表某个对象的数量的变量:nFiles, nSegments
  • 变量要么全是单数,或者全是复数,避免用例如point和points代表两个不同的变量
  • 表示某个对象编号时,可以采用这两种命名方法:以No为后缀(tableNo, employeeNo),或者以i为前缀(iTable,
    iEmployee) 迭代变量应该以i,j,k为名字,或者以i,j,k为前缀,例如:
for iFile = 1:nFiles
    ...... 
end
  • 采用布尔变量时,尽量使bool变量为真时继续执行,例如我们要判断一个文件是否找到,我们应该定义bool变量:isFound,而不是isNotFound。我们只需要判断if isFound,而不是去判断 if ~isNotFound。
  • 当变量名称中含有缩写时,仍然要保持首字母小写,其余单词仅首字母大写的规则。例如。html不能写成hTML,isUsa不能写成isUSA
  • 要用内置的变量或关键词去给变量命名

1.2 常量

  • 常量,以及全局变量应该全部字母大写,并且用下划线分隔单词
  • 当要定义一组类似的常量的时候,他们的前缀可以是相同的,例如要定义一组颜色的常量:COLOR_RED, COLOR_GREEN, COLOR_BLUE

1.3 结构体

  • 结构体的名字应以大写字母开头
  • 结构体的名字不需要包含在内部的变量名中:例如,要写成Segment.length,而不是Segment.segmentLength

1.4 函数

  • 函数名要反映其功能
  • 函数名应该通通小写,名词中间可以用下划线分隔开
  • 函数名一定要清晰,有意义,例如,要写成computetotalwidth(),而不是compwid()
  • 如果只有一个输出的话,可以以输出量作为函数名字,例如:mean()
  • 没有输出,或者只返回句柄的函数,应该以它具体做什么来命名,例如:plot()
  • 以get/set做前缀,表示用来操作对象或者其属性的函数,例如:getobj(.); setappdata(.)
  • 以compute做前缀,表示用于计算某个变量的函数,表示计算复杂程度很高,例如:computweightedaverage(); computespread()
  • 以find做前缀,表示查找某个元素,某一项的函数,例如:findoldestrecord(.); findheaviestelement(.);
  • 以initialize做前缀,表示构建某个对象的函数,例如:initializeproblemstate(.);
  • 以is做前缀,表示布尔函数,另外还可以采用类似的:has,can,should做前缀。例如:isoverpriced(.); iscomplete(.) ;hasLicense(.); canEvaluate(.); shouldSort(.);
  • 更多类似的前缀:
get/set, add/remove, create/destroy, start/stop, insert/delete,
increment/decrement, old/new, begin/end, first/last, up/down, min/max,
next/previous, old/new, open/close, show/hide, suspend/resume, etc.

1.5 General

  • 有时可以考虑在变量名中加入单位,以免引起混淆,例如弧度,incidentAngleRadians
  • 除了一些缩写很常见的单词以外,需使用完整单词以避免混淆
  • 所有的命名要以英语进行,而不是其他语言

2 文件和组织方式(Files and Organization )

2.1 M文件

  • 模块化,尽可能把大的程序抽象为一个个函数,以便于复用
  • 让交互更清晰,尽可能避免过长的参数列表,或者过多的全局变量
  • 尽可能用已有的函数,不要重复造轮子,不妨在实现一个功能前,多查阅一下文档
  • 在不同文件中反复出现的代码,应该包装入一个函数
  • 当一个函数仅在一个文件中出现,那么它应该作为子函数,写在同一个文件中
  • 为每一个函数都编写一个测试脚本,这是最好的提高代码质量的办法

3 表述(Statements)

3.1 变量和常量

  • 为了保证可读性,所有的变量都不应该被复用(不能有两个用途,除非是内存不够)
  • 相同类型或相关的变量应该一同声明,不相关的变量则不应该一同声明。例如:persistent x, y, z; global REVENUE_JANUARY, REVENUE_FEBRUARY
  • 在文件开头的注释中说明重要的变量,例如:% pointArray Points are in rows with coordinates in columns.
  • 在常量定义的末尾,通过注释说明其含义,用法或约束,例如:THRESHOLD = 10; % Maximum noise level found by experiment.

3.1 全局变量和常量

  • 相比于全局变量,参数传递更有利于代码的清晰和可维护性。我们可以通过使用persistent或者get***data的方式来避免过多的使用全局变量。
  • 减少使用全局常量,如有必要,可以通过将所有全局常量定义在一个m文件中,或者存在.mat文件中

3.2 循环语句

  • 循环变量应在循环前就完成初始化,例如:
result = zeros(nEntries,1);
for index = 1:nEntries
   result(index) = foo(index);
end
  • 尽量减少使用break和continue,因为这不利于可读性
  • 循环的最后一行可以添加注释,用于说明循环到此为止,并且说明循环中执行了哪些任务

3.3 条件语句

  • 避免复杂的条件表达式,如有必要,可以引入临时的逻辑变量代替
  • 通常情况下会执行的语句存放在if下,而异常情况则存放在else部分
  • 一般不用使用 if 0 这样的表达,偶尔用来注释代码倒是也可以接受
  • switch语句中,需要包括otherwise这一项
  • switch变量最好是字符串

3.4 General

  • 不要写密码(看不懂的东西)
  • 多写括号
  • 表达式中不要出现太多数字,并且某些经常需要进行修改的数字,应该定义为常量
  • 避免出现THRESHOLD = .5,而应该写成THRESHOLD = 0.5

4 排版,注释和文档(Layout, Comments and Documentation)

4.1 排版

  • 缩进有利于展示代码结构
  • 内容要保持在前80列里
  • 换行的位置要恰当,例如标点符号处,空格处,操作符处,并且新行的开头要与之前的表达式对齐:
totalSum = a + b + c + …
           d + e;
function (param1, param2,…
          param3)
setText ([‘Long line split’ …
         ‘into two parts.]);
  • 缩进大约为3个或者4个空格
  • 一般来说,一行代码只应包括一行可执行语句

4.2 空格

  • 在=,&和|的左右需要插入空格,例如:simpleSum = firstTerm+secondTerm;
  • 在常用的操作符左右最好插入空格,但这是由争议的,例如:simpleAverage = (firstTerm + secondTerm) / two;
  • 逗号后面加空格,例如:foo(alpha, beta, gamma)
  • 代码块中间要用几个空行进行分隔,一般是用三行。也可以使用: %*******************,或者%----------------

4.3 注释

  • 经验表明,最好是在编写代码的同时,添加注释,而不是写完以后再加
  • 注释要和代码一致,否则会误导读者。而又不能只是复述代码,注释要说明的是how和why,而不是what
  • %后面可以跟一个空格,注释的第一个字母可以大写
  • 函数头的注释要便于对函数进行查找,以及说明函数用法
  • 函数头的注释要说明对输入参数的具体要求,例如:
% ejectionFraction must be between 0 and 1, not a percentage.
% elapsedTimeSeconds must be one dimensional.
  • 所有的注释要用英语书写

4.4 文档

  • 差的文档也比没有文档要好
  • 文档需要包括的内容有,运行的需求,功能,函数接口,测试方法等
  • 最好是在写代码之前就先完成文档框架的搭建
  • 使用专业的版本控制工具

5 函数头注释规范:

参考博客:如何规范地编写一个MATLAB函数文件

通常,函数文件由函数声明行、H1行、在线帮助文本区、编写和修改记录、函数主体等几个部分组成。格式如下:

function 输出形参表 = 函数名(输入形参表)
在线帮助文本区,其中第一行为H1行
编写和修改记录
函数主体

  • H1行是紧随函数声明行之后的以“%”开头的第一注释行。H1行包括大写的函数名和函数功能简要描述,采用lookfor命令可在命令行窗口显示H1行的信息。建议在编写H1注释行时,尽量采用英文表述,这是为了之后的使用过程中关键词检索的方便。
  • 在线帮助文本区是包括H1行以及H1行之后的连续的以“%”开头的注释行。通常包括函数输入变量和输出变量的含义以及调用说明。采用help命令可在命令行窗口显示在线帮助文本区的信息。
  • 编写和修改记录与在线帮助文本区以一个空行相隔。该行以“%”开头,记录了编写及修改函数文件的作者、日期、版本等内容,以方便后来的使用查询或修改。
  • 函数主体应与编写和修改记录以一个空行相隔。这部分内容包括了所有实现该函数文件功能的MATLAB指令。

如下是一个实例:

function spir_len = spirallength(d, n, lcolor)                                     <<<  函数声明行
% SPIRALLENGTH plot a circle of radius as r in the provided color and calculate its area <<< H1行
% 输入参数:                                                                     <<< 在线帮助文本区
%   d: 螺旋的旋距
%   n: 螺旋的圈数
%   lcolor:画图线的颜色
% 输出参数:
%   spir_len:螺旋的周长
% 调用说明:
%   spirallength(d,n):以参数d,n画螺旋线,螺旋线默认为蓝色
%   spirallength(d,n,lcolor):以参数d,n,lcolor画螺旋线
%   spir_len = spirallength(d,n):计算螺旋线的周长,并以蓝色填充螺旋线
%   spir_len = spirallength(d,n,lcolor):计算螺旋线的周长,并以lcolor颜色填充螺旋线 <<< 在线帮助文本区
 
% 版本号V1.0,编写于199999号,修改于1999910号,作者:亚索                   <<< 编写与修改记录
 
if nargin > 3                                                                   <<< 函数主体
    error('输入变量过多!');
elseif nargin == 2
    lcolor = 'b'; % 默认情况下为蓝色
end
 
j = sqrt(-1); 
phi = 0 : pi/1000 : n*2*pi; 
amp = 0 : d/2000 : n*d; 
spir = amp .* exp(j*phi); 
 
if nargout == 1
    spir_len = sum(abs(diff(spir))); 
    fill(real(spir), imag(spir), lcolor); 
elseif nargout == 0
    plot(spir, lcolor); 
else
    error('输出变量过多!'); 
end
 
axis('square'); 

参考文献

Richard Johnson. MATLAB Programming Style Guidelines. 2002

你可能感兴趣的:(机器人工程师的成长札记,编程基础知识)