前言
有时候看不懂代码,可以直接去debug一些模块,写一些单元测试。虽然Erlang提供了专门的单元测试方法,但由于没有整体配置(暂时不想二次开发),有一些模块无法启动,所以干脆只把需要的代码拷贝出来做debug观察数据,从而理解原理。整个分析基于EMQ2.3.11。
一、调试方法
1、准备好一个空Erlang工程
参考《EMQ源码分析(一):在Windows上用IDEA搭建Erlang编译平台》,构建一个Helloworld就好。
2、拷贝代码
将需要测试的部分代码从EMQ里面拷贝出来,例如我想要了解订阅树如何构建的,就需要了解Topic如何被切分成三元组的,三元组具体的数据又是怎样的,把emqttd_trie、emqttd_topic相关代码拷贝出来:
erlang
-module(hello).
-author("BEWINDOWEB").
-import(lists, [reverse/1]).
%% API
-type(word() :: '' | '+' | '#' | binary()).
-type(words() :: list(word())).
-type(triple() :: {root | binary(), word(), binary()}).
-type(topic() :: binary()).
-export([start/0]).
-spec(triples(topic()) -> list(triple())).
triples(Topic) when is_binary(Topic) ->
triples(words(Topic), root, []).
triples([], _Parent, Acc) ->
reverse(Acc);
triples([W|Words], Parent, Acc) ->
Node = join(Parent, W),
triples(Words, Node, [{Parent, W, Node}|Acc]).
%% @doc Split Topic Path to Words
-spec(words(topic()) -> words()).
words(Topic) when is_binary(Topic) ->
[word(W) || W <- binary:split(Topic, <<"/">>, [global])].
word(<<>>) -> '';
word(<<"+">>) -> '+';
word(<<"#">>) -> '#';
word(Bin) -> Bin.
join(root, W) ->
bin(W);
join(Parent, W) ->
<<(bin(Parent))/binary, $/, (bin(W))/binary>>.
bin('') -> <<>>;
bin('+') -> <<"+">>;
bin('#') -> <<"#">>;
bin(B) when is_binary(B) -> B.
start() ->
io:fwrite("Hello, world!\n"),
Triples = triples(<<"a/b/c">>),
Triples2 = triples(<<"a/+/c">>).3、断点调试
打上断点调试,就能得到自己想看的数据,从而理解原理:

二、控制台格式化输出
有时候debug的数据不正确(比如位串会以有符号8位来显示),这时需要fwrite,和printf类似。
fwrite可以类似printf去简单控制输出格式,标准格式如下:
erlang
~F.P.PadModC1、不带参数示例
erlang
io:fwrite("123").2、格式化参数示例
erlang
% io:fwrite("~F.P.C",data).
io:fwrite("|~10.5s|~n|",[<<"aaa">>]).
% | aaa |
% |~类似%;F:输出长度,10代表总共10位;P:输出精度,5代表a有5位;C:输出格式,s代表字符串输出,n代表换行符;<<"aaa">>是<<$a,$a,$a>>的语法糖;- 其余字符按正常字符输出。
所以最后的第一行包含了|+5个空格+3个a+2个空格+|,第二行只有|。
3、格式化参数的含义
| 符号C | 含义 | F | P | 参数 |
|---|---|---|---|---|
~c | ascii码 | 最大长度 | 重复次数 | |
~f | 浮点数 | 最大长度 | 精度 | |
~e | 科学计数法 | 最大长度 | 精度 | |
~n | 换行符 | 最大次数 | 重复次数 | |
~s | 字符串 | 最大长度 | 截取长度 | |
~w | 任意元 | 最大长度 | 字串长度 | |
~W | ~w、限制打印深度 | 最大长度 | 字串长度 | 深度 |
~p | 任意元、适当换行和缩进、列表输出为字串 | 单行/多行 | 缩进长度 | |
~P | ~p、限制打印深度 | 单行/多行 | 缩进长度 | 深度 |
~b | 进制整数(小写字母) | 最大长度 | 进制 | |
~B | 进制整数(大写字母) | 最大长度 | 进制 | |
~x | 带任意前缀进制整数(小写字母) | 最大长度 | 进制 | 前缀 |
~X | 带任意前缀进制整数(大写字母) | 最大长度 | 进制 | 前缀 |
~+ | 带进制前缀整数(小写字母) | 最大长度 | 进制 | |
~# | 带进制前缀整数(大写字母) | 最大长度 | 进制 |
4、格式化参数上下界的意义
| 符号C | 小于最大长度F | 超过最大长度F | 小于精度P | 超过精度P |
|---|---|---|---|---|
~c | 左侧补空格 | 报错 | 右侧补空格 | 截断 |
~f | 左侧补空格 | 输出* | 小数点后补0 | 小数点后截断 |
~e | 左侧补空格 | 输出* | 小数点后补0 | 小数点后截断 |
~n | (最大次数) | (最大次数) | (重复次数) | (重复次数) |
~s | 左侧补空格 | 报错 | 右侧补空格 | 从头部开始截断 |
~w | 左侧补空格 | 输出* | - | 输出* |
~W | 左侧补空格 | 输出* | - | 输出* |
~p | (0单行/1多行) | (0单行/1多行) | (缩进长度) | (缩进长度) |
~P | (0单行/1多行) | (0单行/1多行) | (缩进长度) | (缩进长度) |
~b | 左侧补空格 | 输出* | (进制) | (进制) |
~B | 左侧补空格 | 输出* | (进制) | (进制) |
~x | 左侧补空格 | 输出* | (进制) | (进制) |
~X | 左侧补空格 | 输出* | (进制) | (进制) |
~+ | 左侧补空格 | 输出* | (进制) | (进制) |
~# | 左侧补空格 | 输出* | (进制) | (进制) |
5、格式化参数实例
erlang
start() ->
io:fwrite("[c]~10.3c~n",[$a]),
% [c] aaa
io:fwrite("[f]~10.1f~n",[1.23]),
% [f] 1.2
io:fwrite("[e]~10.2e~n",[1.23]),
% [e] 1.2e+0
io:fwrite("[n]~2.9n"),
% [n]
%
io:fwrite("[s]~10.3s~n",["aaabbbbbbb"]),
% [s] aaa
io:fwrite("[w]~60.90w~n",[{"1231231231","aaaaaa"}]),
% [w] {[49,50,51,49,50,51,49,50,51,49],[97,97,97,97,97,97]}
io:fwrite("[W]~60.30W~n",[{"1231231231","aaaaaa"},5]),
% [W] {[49,50,51|...],[97,97|...]}
io:fwrite("[p]~3.0p~n",[{"123123","123123","aaaa"}]),
% [p]{"123123",
% "123123",
% "aaaa"}
io:fwrite("[P]~1.20P~n",[{"123123","123123","aaaa"},10]),
% [P]{"123123",
% "123123",
% "aaaa"}
io:fwrite("[b]~10.16b~n", [109]),
% [b] 6d
io:fwrite("[B]~10.16B~n", [109]),
% [B] 6D
io:fwrite("[x]~10.16x~n", [109,"prefix"]),
% [x] prefix6d
io:fwrite("[X]~10.16X~n", [109,"prefix"]),
% [X] prefix6D
io:fwrite("[+]~10.16+~n", [109]),
% [+] 16#6d
io:fwrite("[#]~10.16#~n", [109]).
% [#] 16#6D6、Pad、Mod
Pad可以指定填充符号,默认空格:
erlang
io:fwrite("[c]~10.3.+c~n",[$a]).
% [c]+++++++aaaMod可以指定模式,只有t可以选择,t表示unicode:
erlang
io:format("~s",[<<"三颗豆子"/utf8>>]),
% 三颗豆子
io:format("~ts",[<<"三颗豆子"/utf8>>]).
% \x{4E09}\x{9897}\x{8C46}\x{5B50}


粤公网安备44030602007943号