MATLAB编程风格
链接:https://www.zhihu.com/question/20103967/answer/2143072715
编程风格也是很重要的,尤其对于初学者更应该注重这方面的习惯培养,其实各语言间的编码风格大体上都是共用的,下面以Matlab这个语言的编程风格为例,说明一下:
目录
谈起MATLAB编程风格,本公号在推文 MATLAB的编码风格建议 中有过介绍。说来惭愧,这只是我平时在编程工作中得到的一些总结把它分享给了有需要的朋友,但涉及面不是很全面。
可以说,每门编程语言都有自己的编码风格,比如很火的python语言,有PEP:8 编程规范。当然了,对于matlab也有它自己的编程风格。matlab社区有本名为《MATLAB styles Guidelines 2.0》的电子书,下载地址:http://datatool.com/downloads/MatlabStyle2%20book.pdf
《MATLAB styles Guidelines 2.0》以精简的语言叙述了matlab应有的编程风格,全书共43页。先看看读者们对这本书的评价:
我认为这个文档封装了大量与许多编程语言相关的好建议,包括一些具体的MATLAB示例。——Penny Anderson
真的有帮助。在开始编写任何代码之前,每个人都应该阅读这样的内容!(现在,该轮到我回顾我所做的一切了) ——Frederic Bosche
这个pdf文件很容易理解,对有MATLAB经验的程序员特别有用。这些指南帮助我构建了一个更加标准化、易于维护的程序。无论你使用哪种语言,都会有一些概念可以参考。——Fu-Sung Wang
清晰、简洁、合理。应该对我(和其他人)有很多帮助。谢谢。——Richard Kirkeeide
简洁而全面。 ——William Zimmerman
一部优秀的收藏品,非常适合初学者或中级Matlab程序员。——Michael Villalba
非常好的指南! 我希望我能跟着他们!——Fahad Al Mahmood
很有帮助。我通常用MATLAB编写程序,我以前没有读过有关风格指南的内容。这将帮助我编写更易读和更易于维护的MATLAB代码。——B G
伟大的工作。这份文档写得很好,也很准确。MATLAB社区急需的一个补充。——Matthew Simoneau
相信认真看完上述评论的朋友们也想很快读完这本简短的电子书,就像Frederic Bosche所说的 “在开始编写任何代码之前,每个人都应该阅读这样的内容!”。因此,为了方便查阅,我将这本电子书进行了一次翻译,由于翻译水平有限,文中难免会有不当之处,还请朋友们批评指正,谢谢!
译文开始
介绍
编写代码的建议通常涉及效率问题,比如“不要使用循环”。这份文档不是这样的。它关注的是正确性、清晰性和概括性。这些指南的目的是帮助生成更可能正确、可理解、可共享和可维护的代码。
有些编码方法比其他的好。就是这么简单。编码规范通过帮助使错误变得明显而增加了价值。正如Brian Kernighan所写,“写得好的程序比写得差的程序要好——它们错误更少,更容易调试和修改——所以从一开始就考虑编码风格是很重要的。”
当人们看你的代码时,他们会看到你在做什么吗?这份文档的主旨可以简单地表达为“避免只写代码”。
本文档列出了与软件开发社区的最佳实践相一致的MATLAB编程建议。这些指南通常与C、C++和Java的指南相同,只是针对MATLAB的特性和历史进行了修改。这些编程建议基于收集了大量源代码的其他语言的指南和个人的经验。这些指南是基于MATLAB编写的,它们也应该对相关语言有用,比如Octave,Scilab和O-Matrix。
随着MATLAB语言的变化和它的使用越来越广泛,风格问题变得越来越重要。在早期版本中,所有变量都是双精度矩阵;现在有许多可用数据类型。使用已经从小规模的原型代码发展到由团队开发的大型和复杂的产品代码。与Java集成是标准的,Java类可以出现在MATLAB代码中。所有这些变化都使得编写清晰的代码变得更加重要和更具挑战性。
指南不是命令,其目的只是帮助程序员写出好的代码。许多组织有理由背离这些指南中的一部分,但是大多数组织将受益于采用这样一些风格指南。
对于MATLAB风格和最佳开发实践的更广泛和更深入的讨论,请查看这本书:《The Elements of MATLAB Style》由http://datatool.com/resources.html
或者亚马逊上获得。
MATLAB是MathWorks公司的注册商标。在本文档中,MathWorks指的是MathWorks公司。
如果您有任何修改或意见,请联系richj@datatool.com。
命名约定
软件命名约定的目的是为了帮助读者和程序员。为一组开发人员建立命名约定是非常重要的,但这个过程可能会产生荒谬的争议。没有一种命名约定会让每个人都满意。
遵守一种约定比这种约定的细节更重要。本节描述一种常用的约定,许多MATLAB和其他语言的程序员都会熟悉这种约定。
变量
变量名应该记录它们的含义或用途。MATLAB能够处理这样的语句
z = x * y
但下面这样做会对读者更好
wage = hourlyRate * nHours
从小写开始用混合大小写命名变量名
这在其他语言中是常见的做法。在其他语言中以大写开头的名称通常是为类型或者结构体保留的。
linearity,credibleThreat,qualityOfLife
很短的变量名可以是大写的,如果它们在常规用法中是大写的,并且不太可能成为复合变量名的一部分。例如在特定领域,杨氏模量的E,可能会被误导为e。
有些程序员喜欢用下划线来分隔复合变量名的各个部分。这种方式虽然易于阅读,但在其他语言中并不常用来命名变量。在图形标题、标签和图例的变量名中使用下划线的另一个考虑因素是,MATLAB中的Tex解释器将把下划线转换为下标来读取,因此需要为每个文本字符串应用参数/值对进行设置,即‘Interpreter’,'none' 。
具有大作用域的变量应该具有有意义的命名,作用域小的变量可以有简短的命名
在实践中,大多数变量都应该具有有意义的名字。在某些条件下,应保留使用简短的命名,以澄清陈述的结构或与预期的通用性相一致。例如,在一个通用函数中,可以使用诸如x, y, z, t这样的变量名。
用于临时存储或索引的临时变量可以保持简短。程序员阅读到这些临时变量时应该能够假定它们的值在几行之外的代码没有被使用。作为整数使用的临时变量的常见命名是k,m,n;双精度变量命名为s,t,x,y和z。处理复数的程序可以选择保留 i 或 j,或者两者都保留为 -1 的平方根。然而,MathWorks推荐使用 1i 或 1j 作为虚数。因为它们执行得更快,而且不能被覆盖。(译者注 : i 和 j 在MATLAB中都作为虚数来使用,一些程序员在 for 循环中习惯使用 i 和 j 作为迭代变量名,这会覆盖掉MATLAB中保留的 i 或者 j,因此不推荐这种做法,可以用双写 ii 或者 jj 作为迭代变量名。)
用前缀 n 来表示对象数量的变量名
这种表示法来自于数学,在数学中,它是用来表示物体数量的既定惯例。如
nFiles,nSegments
一个MATLAB特有的选择是用m表示行数(基于矩阵表示法),如
mRows
遵循多元化的一致性惯例
应该避免两个变量的命名在结尾仅相差一个字母 s。有些程序员把所有变量名都写成单数或复数,但其他人发现这样做很尴尬。
复数形式的一个可接受的用法是使用像 Array 这样的后缀。如
point,pointArray,pointList
单数形式的用法是使用像 this 这样的前缀。如
thisPoint
大多数程序员不会将 the 作为单个示例或元素的前缀。
用后缀 No 或 Num 或前缀 i 表示单个实体号的变量名
No 符号来自于数学,它是表示实体号的既定惯例。
tableNo,employeeNo
前缀 i 有效地使变量成为命名迭代器。
iTable,iEmployee
用 i, j, k 等作为迭代器变量名的前缀
这个符号来自数学,它是指示迭代器的既定惯例。
for iFile = 1:nFiles
:
end
有些程序员使用单字母变量名 i、j 或两者,以方便循环迭代器。使用显式复数的程序员往往讨厌这种做法。
对于嵌套循环,迭代器变量名通常应该按字母顺序排列。一些面向数学的程序员使用以 i 开头的变量名表示行,以 j 开头的变量名表示列。
特别是对于嵌套循环,使用迭代器变量名是很有帮助的。
for iFile = 1:nFiles for jPosition = 1:nPositions : end : end
避免否定的布尔变量名
当这样一个否定的变量名与逻辑否定运算符一起使用时,会出现双重否定问题。像下面的命名并不是显而易见的
~isNotFound
应该使用isFound和~isFound避免使用isNotFound
首字母缩略词,即使通常是大写的,也应该写成混合或小写
全部使用大写将与标准命名约定不一致。这种类型的变量必须命名为
dVD、hTML
等,显然这样的可读性并不高。当这样的命名与另一个命名相连接时,可读性会严重降低。这个缩写后面的单词并不像它应该的那样突出。
应该使用
html,isUsaSpecific,checkTiffFormat()避免使用hTML,isUSASpecific,checkTIFFFormat()
避免使用关键字或特殊的值名作为变量名
如果MATLAB的任何保留字或内置的特殊值被重新定义,那么它会产生神秘的错误消息或奇怪的结果。命令
iskeyword
列出保留字。特殊值在文档中列出。
使用特定领域中通用的命名
如果软件的目标是学科领域或用户组,请使用与标准惯例一致的名称。
应该使用roi,regionOfInterest
避免使用imageRegionForAnalysis
避免遮蔽函数的变量名
在MATLAB产品中,有几个函数名称似乎很容易被用作变量名。在脚本中使用与函数同名的变量会遮蔽函数,并可能引起错误。在函数中使用同名的变量和函数也可能会引起错误。
在代码示例中作为变量出现的一些标准函数名是alpha,angle,axes,axis,balance,beta,contrast,gamma,image,info,input,length,line,mode,power,rank,run,start,text,type
使用众所周知的函数名作为变量名也会降低可读性。如果想在变量名中使用标准函数名,比如length,那么可以添加一个限定符,比如单位后缀,或者名词或形容词前缀:lengthCm,armLength,thisLength
避免匈牙利表示法
至少有两个版本的匈牙利符号已经被一些软件开发人员使用。匈牙利语变量名通常包含1或2个前缀、一个根名称和一个后缀限定符。这些名称可能非常难看,特别是当它们是一串缩写时。如果像通常建议的那样,对数据类型用前缀进行编码,则会出现更大的问题:后来如果需要更改类型,则需要更改变量名的所有关联项。
应该使用thetaDegrees
避免使用uint8thetaDegrees
常量
MATLAB语言没有真正的常量(除了作为对象中的常量属性)。使用标准惯例来命名和定义常量,以便能够识别它们,并且不会无意中重新定义它们。
具有局部作用域(在m文件中)的常量名应该全部大写,并使用下划线分隔单词
这在其他语言中是常见的做法。
MAX_ITERATIONS
, COLOR_RED
对常量使用有意义的名称
应该使用
MAX_ITERATIONS
避免使用
TEN
, MAXIT
由具有相同名称的函数输出的常量名称应全部为小写或混合大小写
MathWorks 使用这种做法,例如,常数pi
实际上是一个函数。
offset
, standardValue
常量可以用通用类型名作为前缀
这提供了关于哪些常量是属于一类的以及这些常量代表什么概念的额外信息。
COLOR_RED
, COLOR_GREEN
, COLOR_BLUE
结构体
结构体命名应以大写字母开头
这种用法与其他语言是一致的,它有助于区分结构体和普通变量。
结构体的命名是隐式的,不需要包含在字段名中
重复使用是多余的。
应该使用
Segment.length
避免使用
Segment.segmentLength
注意字段名
(译者注 :字段名也就是结构体成员名)。当您设置一个结构体字段的值时,如果该字段已经存在,MATLAB将替换现有的值,如果不存在,则创建一个新字段。如果字段名不一致,这可能会导致意想不到的结果,例如,当一个结构体有您想要更新的字段
Acme.source = 'CNN';
但您输入
Acme.sourceName = 'Bloomberg';
结构体现在将会有两个字段。
函数
函数名应该记录它们的用途
用小写或混合大小写命名函数名
最初所有的MATLAB函数名都是小写的。
linspace
, meshgrid
MathWorks 提供的几乎所有函数仍然遵循这一惯例。对于较长的复合名称,如非常规的名称,这种做法可能不是很合适。
isequalwithequalnans
在其他语言中,通常使用从小写开始的混合大小写命名函数名。许多MATLAB程序员遵循这一惯例。
predictSeaLevel
, publishHelpPages
有些程序员喜欢在函数名中使用下划线,但这种做法并不常见。
使用有意义的函数名
MATLAB有一个不幸的传统,即使用简短且通常有些含义模糊的函数名——可能是由于旧的DOS 8字符限制。这个问题已经不重要了,通常应该避免使用传统方法来提高可读性。
应该使用
computeTotalWidth
避免使用
compwid
一个例外是在数学中广泛使用的缩写或首字母缩写。
max
, gcd
具有这样短名称的函数应该在注释行开头中有清晰的描述。
有一个输出的函数要基于其输出命名
这是MathWorks代码中的常见做法。
mean
, standardError
没有输出参数或只返回句柄的函数应该根据它们的作用命名
这种做法提高了可读性,让函数应该做什么(可能不应该做什么)变得清晰。这使得代码更容易避免意外的副作用。
plot
为访问对象或属性的函数保留前缀get/set
这是MathWorks和其他语言的普遍做法。一个可能的例外是将set用于逻辑集合操作。
getobj
, setAppData
为需要计算的函数保留前缀compute
一致使用这个词语可以提高可读性。给读者一个直接的线索,这个函数在做什么。
computeWeightedAverage
, computeSpread
避免可能使人困惑的选择,如find
或make
。
考虑为查找的函数保留前缀find
给读者一个直接的线索,这是一个简单的查找方法,涉及的计算最少。使用一致的术语可以提高可读性,而且它可以很好地替代过度使用的前缀get。
findOldestRecord
, findTallestMan
考虑在创建对象或变量时使用initialize前缀
美式的initialize应优于英式的initialise 。避免缩写init。
initializeProblemState
使用前缀 is 命名布尔函数
这是MathWorks代码和其他语言中的常见做法。
isOverpriced, iscomplete
在某些情况下有一些替代 is 前缀的方法更适合。这些前缀包括 has, can 和 should。
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
, open/close
, show/hide
, suspend/resume
, 等等。
避免无意的隐藏
一般来说,函数名应该是唯一的。隐藏(具有两个或多个同名函数)增加了意外行为或错误的可能性。可以使用which -all
或exist
来检查命名是否存在。
重载函数当然会有相同的名称。当多态函数足够时,不要创建重载情况。
通用
为有维变量和常量考虑使用单位后缀
在一个项目中使用一组单位是一个很有吸引力的想法,但却很少被完全实现。添加单位后缀有助于避免几乎不可避免的意外混合单位表达式。
incidentAngleRadians
尽量减少命名中的缩写
使用完整的单词可以减少歧义,并有助于使代码自文档化。
因该使用
computeArrivalTime
避免使用
comparr
特定领域的短语通过缩写或首字母缩写很自然地被大家所熟知,应该保持缩写。即使是这些情况,也可以在第一次出现时使用注释来定义说明。
html
, cpu
, cm
考虑让命名发音
至少可以发音的名字更容易阅读和记忆。
用英文命名
MATLAB是用英语编写的,而英语是国际开发的首选语言。
语句
变量与常量
除非内存限制要求,否则变量不应该被重用
通过确保所有概念都被唯一地表示来增强可读性。减少因误解定义而产生错误的机会。
考虑在文件开始附近的注释中记录重要变量
其他语言的标准做法是在声明变量的地方记录变量。由于MATLAB不使用变量声明,这些信息可以在注释中提供。
% pointArray Points are in rows. THRESHOLD = 10; % Maximum noise level found.
全局变量
尽量少使用全局常量
使用m文件或mat文件来定义全局常量。这一惯例明确了常量的定义位置,并防止了无意的重新定义。如果m文件的访问产生了执行速度开销问题,考虑使用函数句柄。
尽量少使用全局变量
函数的清晰性和可维护性得益于显式参数传递,而不是使用全局变量。某些全局变量的使用可以用更清晰的persistent
或getappdata
来替换。另一种策略是用一个函数替换全局变量。
循环
在循环之前立即初始化循环结果变量
初始化这些变量可以提高循环速度,并帮助防止在循环没有对所有可能的索引执行时出现假值。这种初始化有时称为预分配。将初始化放在循环的前面,可以更容易地看到变量已初始化。这种做法还使复制所有相关代码以在其他地方使用变得更容易。
result = nan(nEntries, 1); for index = 1:nEntries result(index) = foo(index); end
在初始化语句和for
行中使用一个命名变量作为参数。
尽量减少在循环中使用break
这个关键字通常是不必要的,只有当它证明比结构化的替代具有更高的可读性时才应该使用。
尽量减少在循环中使用continue
这个关键字通常是不必要的,只有当它证明比结构化的替代具有更高的可读性时才应该使用。
嵌套循环中的end行可以有辨认注释
在长嵌套循环的end
行中添加注释,可以帮助澄清哪些语句位于哪些循环中,以及在这些点上执行了哪些任务。
条件句
避免复杂的条件表达式,而是引入临时逻辑变量
通过将逻辑变量赋值给表达式,程序可以自动获取文档。这样的构造将更易于阅读和调试。
if (value>=lowerLimit)&(value<=upperLimit)&~ismember(value,… valueArray)
:
end
应改为:
isValid = (value >= lowerLimit) & (value <= upperLimit);
isNew = ~ismember(value, valueArray);
if (isValid & isNew)
:
end
把常用的实例放在if-部分,把不常用的实例放在if else语句的else-部分
这种做法通过防止特殊情况遮挡正常的执行路径来提高可读性。
fid = fopen(fileName);
if (fid~=-1)
:
else
:
end
如果为0,则避免使用条件表达式
确保这种用法不会妨碍正常的执行路径。要暂时绕过代码执行,请使用编辑器的块注释特性来代替此表达式。
switch语句应该包含otherwise条件
忽略otherwise选项是一个常见的错误,它可能会导致意想不到的结果。
switch (condition)
case ABC
statements;
case DEF
statements;
otherwise
statements;
end
当条件以表达式的形式写得最清楚时,使用if。当条件最清楚地写成变量时,使用switch
if
和switch
的用法可能有重叠。遵循此指导原则有助于提供一致性。switch
变量通常应该是一个字符串。字符串在这种上下文中工作得很好,它们通常比枚举情形更有意义。(译者注:这一观点我不太赞成,毕竟在构建大型项目时,使用枚举类要比字符串灵活得多,可读性也更好。)
通用
避免含义模糊的代码
也许是受到了莎士比亚的一句名言“简洁是智慧的灵魂”的启发,一些程序员有一种倾向,写出简洁甚至晦涩的MATLAB代码。编写简洁的代码是探索语言特性的一种方式。然而,在几乎所有的情况下,清晰应该是目标。正如MathWorks的Steve Lord所写的那样,“从现在起一个月后,如果我看到这段代码,我能理解它在做什么吗?”
使用括号
MATLAB已经记录了运算符优先级的规则,但是谁想记住细节呢?如果有疑问,可以用括号来说明。它们对扩展逻辑表达式特别有帮助。
尽量减少在表达式中使用数字
可能发生变化的数字通常应该命名为常量。如果一个数字本身没有明显的含义,则通过引入一个命名常量来增强可读性。更改常量的定义要比查找和更改文件中出现的所有相关数字容易得多。
在小数点前写一个数字的小数值
这符合数学惯例的语法。此外,0.5
比.5
更具可读性;它不太可能被读取为整数5
。
应该使用
THRESHOLD = 0.5;
避免使用
THRESHOLD = .5;
谨慎使用浮点数做比较
浮点数做逻辑比较可能会引起麻烦,如本例所示。
shortSide = 3; longSide = 5; otherSide = 4; longSide^2 == (shortSide^2 + otherSide^2) ans = 1
但是
scaleFactor = 0.01; (scaleFactor*longSide)^2 == ((scaleFactor*shortSide)^2 + … (scaleFactor*otherSide)^2) ans = 0
一个更好的方法是测试值之间的差异是否足够小。
使用自然、简单的形式来表达逻辑表达式
包括否定在内的逻辑表达可能很难理解。努力使用肯定表达。
应该使用
iSample >= maxSamples;
避免使用
~(iSample < maxSamples);
为错误做准备
一般来说,错误应该在底层例程中捕获,并在高层例程中固定或传递,以便解决。防止出现错误的一个有用工具是用try catch结构捕获异常。另一种方法是if语句中使用正确顺序的表达式,可以避免表达式中的求值导致的错误。
在函数中包含有效性检查以便捕获输入
无效的输入通常会导致程序停止运行的错误。有效性检查允许更优雅的处理错误。有用的工具包括validateattributes
和inputParser
。
尽可能避免使用eval
与其他选择相比,涉及eval
的语句往往更难正确编写,更难阅读,执行也更慢。eval
的使用不支持通过M-Lint
来校验。使用eval
的语句通常可以通过将命令转换为函数,或者对带有setfield
和getfield
的结构使用动态字段引用来改进。
尽可能将代码编写为函数
函数通过使用不属于基本工作空间的内部变量来模块化计算。它们使输入和输出变量更明显,而且比脚本更清晰、更灵活、设计更好。脚本的主要角色是在开发中,因为它们提供了变量维度、类型和值的直接可见性。
编写自动化代码
尽量减少keyboard
和input
的使用,以支持自动执行和测试。
布局、注释和文档
布局
布局的目的是帮助读者理解代码。缩进排版对于显示代码结构特别有帮助。
保持每一行的内容不超过80列
80列是编辑器、终端仿真器、打印机和调试器的常用维度。几个人之间共享的文件应该保持在这些限制之内。如果在程序员之间传递文件时避免了无意的换行,可读性就会提高。
在优雅的地方分开长长的语句
当语句超过建议的80列限制时,就会出现换行。
一般而言:
在逗号或空格后换行
在操作符之后换行
编辑器在延续操作符(...)之后提供缩进。也可以包含额外的空格,使新行与前一行的表达式在开头对齐。
function (param1, param2, … param3) setText([‘Long line split’ … ‘into two parts.’]);
缩进3或4个空格
良好的缩进可能是揭示程序结构的唯一最佳方式。缩进1个空格太小,无法强调代码的逻辑布局。有时建议缩进2个空格,以减少嵌套语句需要停留在80列内的换行数,但MATLAB通常没有深度嵌套。缩进大于4会使嵌套代码难于阅读,因为它增加了必须拆分行的机会。缩进4是MATLAB编辑器中当前的默认值。
与MATLAB编辑器缩进一致
MATLAB编辑器提供了缩进,以澄清代码结构,并与c++和Java推荐的实践一致。如果你使用不同的编辑器,尽量保持一致。
每行写一条可执行的代码语句
这种做法提高了可读性,提高了执行速度。
简短的单个if、for或while语句可以写在一行上
这种做法更紧凑,但它的缺点是没有缩进格式提示。
if(condition), statement; end
while(condition), statement; end
for iTest = 1:nTest, statement; end
MATLAB中的“逗号 ,”
逗号用作分隔符,可以用来分隔数组下标、创建数组时分隔行元素(等同于空格)、
分隔函数的多个输入/输出参数、同一行语句中分隔多个命令(显示输出)。
分隔数组下标,创建数组时分隔行元素,此时等同于空格。
A = [1,2;3 4];
当函数有多个输入/输出参数时,使用逗号将各个参数之间分隔开来。
[M,I] = max(A,[],2);
如果想在同一行中输入多个命令,可以用逗号分隔开来。注意,逗号会显示输出。
A = 1, B = [1,2,3,4]; C = [0,1],
输出结果:(注释掉的部分就是输出结果)
% A = 1
% C = 0 1
上述语句,在同一行中,A,C的赋值以逗号结尾,所以会有输出;B以分号结尾,
所以没有输出。
空格
空各通过使语句的各个组成部分突出以用来增强可读性。
在 = , && 和 || 两边使用空格
在赋值字符两边使用空格提供了一个强大的视觉效果,将语句的左右两侧分开。
在二元逻辑运算符两边使用空格可以澄清复杂的表达式。
simpleSum = firstTerm+secondTerm;
通用的运算符在左右两边加上空格
这种做法存在争议。有些人认为它提高了可读性。另一些人则发现,它使表达变得不必要地冗长。
simpleAverage = (firstTerm + secondTerm) / two; for index = 1 : nIterations
逗号后面可以跟一个空格
这些空格可以增强可读性。一些程序员为了避免分行而省略了它们。
foo(alpha, beta, gamma) foo(alpha,beta,gamma)
如果在一行中有多个命令,在分号或逗号后面加一个空格
间隔提高可读性。
if (pi>1), disp(‘Yes’), end
在关键字后面加空格
这种做法有助于区分关键字和函数名。
在一个块中增加一个空行来分割语句的逻辑归类
在一个块的逻辑单元之间加上空格来增加可读性。
用一个以上的空行分隔块
一种方法是使用三个空行。通过使空间大于块中的空间,这些块将在文件中突出。更好的方法是使用由%%
定义的节。
无论在哪个地方,使用对齐就能提高可读性
代码对齐可以使分离表达式更容易阅读和理解。这种布局还可以帮助揭示错误。
value = (10 * nDimes) + … (5 * nNickels) + … (1 * nPennies);
注释
注释的目的是向代码增加额外的信息。注释的典型用途是解释用法,表达代码的目的,提供参考信息,证明决策,描述限制,提到需要的改进。经验表明,最好是在编写代码的同时编写注释,而不是打算在以后添加注释。
使注释易于阅读
%
和注释文本之间应该有一个空格。注释通常以大写字母开始,以句号结束。
用英文写注释
在国际环境中,英语优先。
头注释
头注释是m文件中第一个连续的注释块。编写它们以向用户提供使用该文件所需的信息。
常用的函数头注释有两种风格。传统样式在函数行下面有注释,并且只使用单个%
符号。它最初是为命令窗口使用而设计的。更现代的样式是在函数行上方添加注释。它通常使用MATLAB标记,并被设计为产生一个帮助和函数浏览器的HTML文件。
在头注释中显示函数语法
用户需要知道输入和输出参数,它们的顺序和变化。
在头注释中讨论输入和输出参数
用户需要知道输入是需要用特定的单位表示,还是需要用特定类型的数组表示。
% completion must be between 0 and 1. % elapsedTime must be one dimensional.
在头注释中描述任何副作用
副作用是函数的操作,而不是输出变量的赋值。一个常见的例子是绘图生成。这些副作用的描述应该包含在头注释中,以便它们出现在帮助打印输出中。
在注释中使用实际的函数名
旧的代码文件经常在头注释中使用全大写的函数名,尽管实际的函数名都是小写的。这种做法可能是为了在无色的命令窗口中突出显示函数名。
现在大多数程序员在编辑器窗口、帮助或函数浏览器中查看帮助信息。在这些上下文中,全大写风格对读者没有帮助。另外,混合大小写的函数名也变得越来越常见,在注释中使用全大写可能会造成混淆。
避免函数头显示混乱
在函数文件的开头附近的注释中包含版权行和更改历史是很常见的。头注释和这些注释之间应该有一个空白行,这样它们就不会显示在帮助文档中。
行内注释
与头注释相反,代码中的注释是为程序员而不是为用户准备的。
注释不能解释写得不好的代码
注释不能弥补缺少适当命名选择和显式逻辑结构的代码。这样的代码应该重写。Steve McConnell: “改进代码,然后将其记录在案,使其更加清晰。”
使注释与代码一致,但不仅仅是重新声明代码
一个糟糕或无用的注释只会妨碍读者。N.Schryer:“如果代码和注释不一致,那么两者都可能是错的。” 注释通常更重要的是说明为什么或者怎么做,而不是说明代码做了什么。
缩进代码注释与引用的语句要相同
当注释不会破坏代码的布局时,代码更容易阅读。
尽量减少句尾行注释的使用
行注释结束的描述性受到典型的80列行长度的限制。一般情况下,它们只能作为变量声明的附加项使用。
文档注释
文档主要针对两类人:希望运行代码的用户和阅读代码的程序员。通常,头注释是为用户准备的,而内联注释是为程序员准备的。
发布注释
MATLAB支持对HTML发布的特殊注释,
XML, latex, doc, ppt和pdf格式。发布到HTML对于函数文档非常有用。将脚本发布为doc或pdf可以生成基本的报告。
MATLAB可以在浏览器中帮助用户显示编写的HTML参考页面。简单的发布功能可以标记MATLAB从这些页面生成的m文件。
文件和组织
在文件之间和文件内部结构化代码对于理解代码是至关重要的。深思熟虑的划分和排序增加了代码的价值。
M文件
模块化
编写大型程序的最佳方法是将设计良好的小块(通常是函数)组装起来。这种方法通过减少必须阅读的文本数量来增强可读性、理解和测试。
超过两个编辑器屏幕的代码可以进行分区。将相关信息放在同一个编辑器屏幕上可以让您看到某些类型的问题并立即修复它们。设计良好的小函数更有可能在其他应用程序中使用。
明确相互作用
函数通过输入和输出参数以及全局变量与其他代码交互。使用参数几乎总是比使用全局变量更清楚。结构体可以用来避免输入或输出参数的列表长度。
标准接口为使用该功能带来了更加熟悉和一致的体验。这使得正确使用的可能性更大。
分块
所有的子函数和许多函数都应该很好地完成一件事。每个函数都应该隐藏一些东西。
利用现成的函数
开发一个正确、可读且相当灵活的函数是一项重要的任务。找到提供部分或全部所需功能的现有函数可能会更快或更可靠。
任何出现在多个m文件中的代码块都应该考虑作为函数来编写
如果代码只出现在一个文件中,那么管理更改就容易得多。尝试使用剪切和粘贴,而不是复制和粘贴。
函数的参数用结构体
函数的可用性随着参数数量的增加而降低,特别是当一些参数是可选的时候。考虑在参数列表超过3时使用结构体。
结构体可以允许更改传递给或从函数传递的值的数量,这与现有的外部代码兼容。
结构体可以消除参数按固定顺序排列的需要。对于可选值来说,结构体比拥有一个长且有序的变量列表更优雅。
在函数中提供一般性
函数通常应该足够灵活,可以接受至少二维的标量、向量和数组输入。带有输入参数的函数通常有多个表示形式,应该使用所有这些参数。例如,图像处理函数至少应该使用uint8和double数据类型。
子函数
在同一个文件中,只有一个函数使用的函数应该打包为其子函数。这使得代码更容易理解和维护。
MATLAB允许从m文件外部访问子函数。这通常是个坏主意。
测试脚本
为每个函数编写一个测试脚本。这样做可以提高函数初始版本的质量和变更版本的可靠性。要考虑到,任何太难测试的函数可能也太难编写。Boris Beizer:“设计测试不仅仅是测试行为,它是已知的最好的漏洞预防者之一。”
输入和输出
制作输入输出模块
要求输出不预先通知地更改。输入格式和内容也会发生变化,而且经常会出现混乱。对处理它们的代码进行本地化可以提高可维护性。
除了预处理之外,避免将输入或输出代码与计算混合在一个函数中。混合用途的函数不太可能被重用。
格式化输出,以便于使用
如果输出很可能被人们阅读,那么让它具有自我描述性以便于阅读。
如果输出更容易被软件读取,而不是被人读取,那么要使其易于解析。
如果这两者都很重要,则应使输出易于解析,并编写一个格式化函数以生成人类可读的版本。
使用feof读取文件
依赖行计数或数据计数很容易导致文件结束错误或输入不完整。
工具箱
组织具有一般性的m文件到工具箱中。检查函数名是否被隐藏。将工具箱位置添加到MATLAB路径中。
通常情况下,同时拥有项目工具箱和通用工具箱是很有用的。
风格引用
Martin Fowler:“任何傻瓜都能写出计算机能理解的代码。优秀的程序员写出人类能理解的代码。
“在风格上,随波逐流;在原则问题上,要像岩石一样站立。” Thomas Jefferson。
“在你打破规则之前,你必须先了解规则。否则就毫无乐趣可言。”《迈阿密风云》的Sonny Crockett。
Patrick Raume,“玫瑰如果不叫玫瑰,就会让问题复杂化。”
柏拉图说:“没有东西是因其本质而得名的,只有惯例和习惯才有它的名字。”
佚名,“所有的一般陈述都是错误的。
尽量避免船长所描述的冷静的局面 “我们现在得到的是沟通的失败。”
Kreitzberg和Shneiderman:“编程可以很有趣,密码学也可以;然而,它们不应该结合在一起。”
Jay Rodenberry:“空格……最后的边界。”
Napoleon Hill ,“思想第一;接着把想法组织成创意和计划;然后把这些计划变成现实。”
“改变无可避免……自动贩卖机带来的改变除外。”
参考文献
The Elements of MATLAB Style, Richard Johnson
Clean Code, Robert Martin
Code Complete, Steve McConnell - Microsoft Press
The Elements of Java Style, Allan Vermeulen et al.
MATLAB: A Practical Introduction, Stormy Attaway
The Practice of Programming, Brian Kernighan and Rob Pike
The Pragmatic Programmer, Andrew Hunt, David Thomas and Ward Cunningham
Programming Style, Wikipedia
MATLAB断言及其他验证示例
assert函数的功能是条件为 false 时引发错误。
语法
assert(cond)
assert(cond,msg)
assert(cond,msg,A1,...,An)
assert(cond,errID,msg)
assert(cond,errID,msg,A1,...,An)
断言条件,指定为有效的 MATLAB 表达式。如果 cond 为 false,assert 函数会引发错误。
cond 可以包含关系运算符(例如 < 或 ==)和逻辑运算符(例如 &&、|| 或 ~)。
使用逻辑运算符 and 和 or 创建复合表达式。MATLAB 按照运算符优先级规则从左至右计算复合表达式。
注意如果希望 MATLAB 转换错误消息中的特殊字符(例如 \t、\n、%s 和 %d),必须为 assert 指定多个输入参数。
数值、字符或字符串数组。此输入参数提供与 msg 中的转换设定符相对应的值,用来替换这些转换设定符。
提示
引发错误时,MATLAB 会捕获该错误的相关信息并将其存储在用作 MException 类的对象的数据结构体中。
可以使用try/catch来访问异常对象中的信息。或者,如果程序由于异常而终止,并将控制权返回至命令提示符,
则可以使用 MException.last。
如果断言失败发生在try块内,则 MATLAB 不会停止执行该程序。在本例中,MATLAB 将控件传递到catch块中。
说明
如果 cond 为 false,assert(cond) 会引发错误。
如果 cond 为 false,assert(cond,msg) 会引发错误并显示错误消息 msg。
如果 cond 为 false,assert(cond,msg,A1,...,An) 会显示一条错误消息,其中包含格式设置转换字符,
例如与 MATLAB® sprintf 函数一起使用的字符。msg 中的每个转换字符都会转换为 A1,...,An 中的一个值。
如果cond 为 false,assert(cond,errID,msg) 会抛出错误并显示错误消息 msg,还会包含一个标示此异常的错误标识符。
此标识符可用于区分错误,它还允许您控制在 MATLAB 遇到错误时系统做何反应。
assert(cond,errID,msg,A1,...,An) 会显示格式化的错误消息,还会包含标示异常的错误标识符。
原文链接:https://blog.csdn.net/jk_101/article/details/111032630