文章目录
- MATLAB 函数签名器
- 注释规范
- 模板
- 参数类型 kind
- 数据格式 type
- 选项的支持
- 使用
- 可执行程序
- 封装为m函数
- 程序输出
- 编译
- 待办事项
- 推荐阅读
- 附录
MATLAB 函数签名器
MATLAB 函数签名器 (FUNCSIGN) ,在规范注释格式的基础上为函数文件或类文件自动生成函数签名,并保存至functionSignatures.json。
函数签名能够允许使用者在编辑器调用这些(自定义)函数的时候具备代码提示和自动填充功能,提升编程体验,更多介绍请阅读 自定义代码建议和自动填充 - MATLAB & Simulink - MathWorks 中国。
👍自定义函数代码提示与自动填充:
注释规范
模板
为了简化自动化步骤,需要对MATLAB的函数文件和类文件的注释格式进行一定的限制和规范,以下为文件注释模板:
function returnValue = functionName(R1, R2, R3, O1, O2, varargin)
%functionName 函数的简要说明
%
% 函数详细说明
%
% Syntax: (这里添加函数的调用格式, `[]`的内容表示可选参数)
% returnValue = functionName(R1, R2, R3 ...
% [, O1, O2 ...
% , 'Coeff', 100 ...
% , 'k', 1.0 ...
% , "Method", "way1"]);
%
% Params:
% - R1 [required] [[char], [string]] R1是char或string
% - R2 [required] [numeric; size=2,2] R2为一个2x2的数值矩阵,注意用分号隔开
% - R3 [required] 可以省略参数数据格式
% - O1 [ordered] [numeric; vector] 可选参数O1
% - O2 [ordered] [numeric; nrows=2] 可选参数O2, 函数简要描述将会被记录
% 可在此处添加O2的详细说明,但是不会被记录到json文件中。
%
% - Coeff [namevalue] [numeric] namevalue对
% 当一个函数存在太多参数设置时, 推荐使用namevalue, 提高可读性, 不需要记忆函
% 数参数位置;
% - k [namevalue] [[numeric], [numeric, choices]] 选项设置
% * 1.0 可添加选项简要描述, 但是不会别记录
% * 2.0 没有用引号括起的选项不能包含空格
% * 3.0 程序会尝试将选项转换为数值,若失败则转换为字符串
% - Method [namevalue] [char; choices] 选项设置
% * 'way1' 方法1
% 选项之间可换行或添加其他说明
%
% * 'way2' 方法2
%
% Return:
% - returnValue 返回值
%
% Note:
% 这里可以添加其他描述
%
% Matlab Version: R2021b
%
% See also:
% myadd, myfun, myfun2, myfun3
returnValue = R1; % 正式代码与注释之间留一个空行
end
关于模板的几点要求❗和建议✔ :
-
❗ 函数文件和类文件必须遵循MATLAB语法规则,不能有语法错误:
-
函数文件
function
必须位于文件首行,且函数名需与函数文件名保持一致; -
类文件
classdef
位于文件首行且类名与类文件名一致;
-
-
✔ 建议文件注释从文件第二行开始,
%
从第一列开始,后跟函数名或类名以及文件简要描述; -
✔注释中存在一些关键字,例如
Syntax
后跟函数调用格式,Params
后跟函数输入参数描述,Return
后跟返回值等。这些关键字中只有Params
是必要的,其他关键字是可选的(也就是说可以自定义增删减改); -
❗
Params
关键字后为函数参数描述内容。注释模板必须要有关键字Params
(关键字后可以紧跟冒号:
),程序检测到Params
关键字后才会解析后续行的函数参数描述,直到注释结束或检测到一个新的关键字; -
❗ 在
Params
后,其他关键字之前的行为函数参数描述,函数的每一个输入参数都需要独立占一行,并且按照如下格式:参数标识符 参数名称 [参数类型] [数据格式] 参数简要说明
-
参数标识符 默认为
-
,检测到此标识符的行才会被解析,否则会跳过此行的,因此允许函数参数描述行之间添加一些对参数的具体描述(具体例子见模板); -
[参数类型] 和 [数据格式] 可以省略,程序会用默认值(
[required]
和[numeric]
)进行替代,但是两者不能互换位置; -
参数简要说明 会被记录到 json 文件;
-
-
✔ 文件注释结尾处与代码之间留一个空行;
参数类型 kind
与 自定义代码建议和自动填充 - MATLAB & Simulink - MathWorks 中国 规定相同,目前支持以下三种类型:
- required 参数是必需的,其位置相对于签名对象中的其他必需参数;
- orderd 参数是可选的,其位置相对于签名对象中的必需参数和前面的可选参数;
- namevalue 参数是可选的名称-值对组,名称-值对组参数出现在函数签名的末尾,但这些对组可以按任意顺序指定。
✔ 参数类型可以使用首字母缩写,即[r]/[R]
来表示[required]
,[o]/[O]
来表示[orderd]
,[n]/[N]
来表示[namevalue]
;
✔ 参数类型 kind 可以省略,默认为 [required]
;
❗ 参数类型 kind 必须位于数据格式 type 之前;
❗ 根据 MATLAB 的要求,函数参数需要按照 required、orderd、namevalue类型依次排列,即函数输入先放必要参数,再放可选参数,最后放namevalue参数。
数据格式 type
与 自定义代码建议和自动填充 - MATLAB & Simulink - MathWorks 中国 基本一致,但又有几点不同,我们将结合 MATLAB 的说明文档进行说明:
type
属性可以定义参数是哪个类以及参数必须具有哪些属性。
-
要匹配一个类或属性,请使用单个 JSON 字符串。例如,如果参数必须是数值,则指定
"type":"numeric"
。注释数据格式为
[numeric]
-
要匹配所有类或属性,请使用 JSON 字符串列表。例如,如果某个参数必须既是数值又是正数,则指定
"type":["numeric", ">=0"]
。注释数据格式为
[numeric; >=0]
-
要匹配多个类或属性中的任意多个,请使用 JSON 字符串列表的列表。在内层列表,MATLAB 对各值执行逻辑 AND 运算。在外层列表,MATLAB 对各值执行逻辑 OR 运算。例如,如果参数必须要么是正数,要么是
containers.Map
对象,则指定"type":[["numeric", ">=0"],["containers.Map"]]
注释数据格式为
[[numeric; >=0], [containers.Map]]
-
提供参数选项
["char", "choices={'way1', 'way2'}"]
注释数据格式为
[char; choices]
,选项由选项行提供
注释数据格式总结为:
- 不需要使用引号括起每一项;
- 同一列表之间项用
;
隔开,它们是并&&
的关系; - 不同列表之间用
,
隔开,不同列表是或||
的关系; - 全新的选项支持
✔ 数据格式 kind 可以省略,则默认为 [numeric]
。
❗ 数据格式 kind 必须位于参数类型 kind 之后。
选项的支持
当数据格式中包含 choices
时,程序会将此行(包含choices
)与下一个包含参数描述/关键字的行之间的行识别为选项行。每一个选项独占一行,选项的描述格式为:
选项标识符 选项名称 选项说明
- 选项标识符 默认为
*
,检测到此标识后此行才会被解析,因此选项之间可以留空或者添加具体的选项描述; - 选项名称 选项名称可以用
'
或"
括起(选项名称可以有空格),或者不用引号(选项名称不允许有空格),选项名称会被记录到 json,程序会尝试将选项名称转换为数字(如果可以),若转换失败则为字符串; - 选项说明 选项简要说明,不会记录到 json,也可以不写。
❗ 选项标识符不能与参数标识符相同!
例 1:
- Method [namevalue] [choices] 选择一个方法
* 'add' 方法1
* 'subtract' 方法2
* 'multi' 方法3
转换 json 字符串为
"choices={'add', 'subtract', 'multi'}"
例 2:
- Method [R] [char; choices] 选择一个方法
* add 方法1
* subtract 方法2
* multi 方法3
转换 json 字符串为
"char", "choices={'add', 'subtract', 'multi'}"
例 3:
- Coeff [R] [int; choices] 选择一个方法
* 1
* 2
* 3
转换 json 字符串为
"int", "choices={1, 2, 3}"
使用
可执行程序
可执行程序为 dst/signfunc.exe,其运行指令为
signfun.exe <DirPath> [-ag -] [-op *] [-ver 1.0.0] [-info on/off] [-kind required] [-type numeric]
其中,必须指定目标文件夹的路径 DirPath,其他几项为可选项:
- -ag 是参数标识符,默认为 -
- -op 是选项标识符,默认为 *
- -ver 是签名文件的版本呢信 息,默认为 1.0.0
- -log 是否输出详细信息,默认为 on
- -kind 设置默认参数kind,默认为 required,不建议修改
- -type 设置默认参数type,默认为 numeric,不建议修改
❗ 注意,需要将可执行程序的路径添加到系统环境路径中。
封装为m函数
封装的m函数为 dst/hs_signfunc.m,其调用格式为
status = hs_signfunc(dir_path ...
[, "Verbose", true ...
, "ArgSym", '-' ...
, "OptSym", '*' ...
, "Version", "1.0.0" ...
, "DefaultKind", 'required' ...
, "DefaultType", {"numeric"}]);
具体的函数参数说明见函数文件 hs_signfunc.m。
注意:
-
❗ 需要将可执行程序 signfunc.exe 的路径添加到系统环境路径中;
-
❗ 需要将m函数文件 hs_signfunc.m 添加到 MATLAB 路径中。
程序输出
程序运行后会在指定目录下生成函数签名文件 functionSignatures.json 和日志文件 funcsigner.log。
可以调用 validateFunctionSignaturesJSON(json_path)
来检验函数签名文件格式是否正确。检查格式无误后,可能需要重启 MATLAB 才能激活自定义函数代码提示功能。
编译
-
源码:https://gitee.com/iam002/funcsign
-
编译环境:
- VSCode + cmake插件+ cpp插件
- cmake
- VS 2019 amd64
✔ 软件安装好后,打开VSCode进入当前文件夹,打开命令面板,执行 cmake configure,在底部改为Release模式,再执行 cmake build target 后选择 install。
-
依赖第三方库(已放置到 thirdparty)
- easyloggingpp
- jsoncpp
当然,也可以通过命令行的方式进行编译
mkdir build cd build cmake -DCMAKE_BUILD_TYPE=Release .. cmake --build . --config Release -A x64 cmake install
等待编译完成后可执行程序保存在 dst,将其添加到系统路径和MATLAB路径,即可使用。
待办事项
-
由于 jsoncpp 不能按照插入顺序进行输出,在调用 validateFunctionSignaturesJSON 会有如下信息。但经实测,函数签名仍有效;
“_schemaVersion” 必须是文件中的第一个属性。
-
为什么不提供 mex 文件
mex 接口对中文支持实在不友好,输入到终端的字符顺序又有点乱😂,目前还没有解决方法;使用
system
调用可执行程序已经很好满足需求了,不再考虑通过mex来封装了。 -
跨平台支持
推荐阅读
- 自定义代码建议和自动填充 - MATLAB & Simulink - MathWorks 中国
- 验证 functionSignatures.json 文件 - MATLAB validateFunctionSignaturesJSON - MathWorks 中国
- 声明函数参数验证 - MATLAB arguments - MathWorks 中国
- iam002/funcsign (gitee.com)
附录
注释模板的函数签名文件:
{
"_schemaVersion" : "1.0.0",
"functionName" :
{
"inputs" :
[
{
"kind" : "required",
"name" : "R1",
"purpose" : "R1是char或string",
"type" :
[
[
"char"
],
[
"string"
]
]
},
{
"kind" : "required",
"name" : "R2",
"purpose" : "R2为一个2x2的数值矩阵,注意用分号隔开",
"type" :
[
"numeric",
"size=2,2"
]
},
{
"kind" : "required",
"name" : "R3",
"purpose" : "可以省略参数数据格式",
"type" :
[
"numeric"
]
},
{
"kind" : "ordered",
"name" : "O1",
"purpose" : "可选参数O1",
"type" :
[
"numeric",
"vector"
]
},
{
"kind" : "ordered",
"name" : "O2",
"purpose" : "可选参数O2, 函数简要描述将会被记录",
"type" :
[
"numeric",
"nrows=2"
]
},
{
"kind" : "namevalue",
"name" : "Coeff",
"purpose" : "namevalue对",
"type" :
[
"numeric"
]
},
{
"kind" : "namevalue",
"name" : "k",
"purpose" : "选项设置",
"type" :
[
[
"numeric"
],
[
"numeric",
"choices={1.0, 2.0, 3.0}"
]
]
},
{
"kind" : "namevalue",
"name" : "Method",
"purpose" : "选项设置",
"type" :
[
"char",
"choices={'way1', 'way2'}"
]
}
]
}
}