修复编译错误后,您仍然面临运行时错误。由于您正在尝试学习 Erlang,因此查看您的方法并查看它是否可以改进并在此过程中修复这些运行时错误是很有启发性的。
首先我们来看swedish_date/0:
swedish_date() ->
[YYYY,MM,DD] = tuple_to_list(date()),
为什么要将列表转换为元组?由于您单独使用列表元素并且从不使用整个列表,因此转换没有任何意义。您可以改为模式匹配返回的元组:
{YYYY,MM,DD} = date(),
接下来,您正在调用 string:substr/1,它不存在:
string:substr((integer_to_list(YYYY,3,4) ++
pad_string(integer_to_list(MM)) ++
pad_string(integer_to_list(DD))).
string:substr/2,3 functions 都采用起始位置,3 元版本也采用长度。你也不需要,并且可以完全避免string:substr,而只是返回组装的字符串:
integer_to_list(YYYY,3,4) ++
pad_string(integer_to_list(MM)) ++
pad_string(integer_to_list(DD)).
哎呀,这还是不对:没有integer_to_list/3这样的功能,所以只需将第一个调用替换为integer_to_list/1:
integer_to_list(YYYY) ++
pad_string(integer_to_list(MM)) ++
pad_string(integer_to_list(DD)).
接下来我们看pad_string/1:
pad_string(String) ->
if
length(String) == 1 -> '0' ++ String;
true -> String
end.
这里有一个运行时错误,因为'0' 是一个原子,而您正试图将String(它是一个列表)附加到它。错误如下所示:
** 异常错误:参数错误
in 运算符 ++/2
称为 '0' ++ "8"
让我们考虑一下pad_string/1 的作用,而不是直接修复它:如果字符串是单个数字,它会添加一个前导0 字符。不要使用if 来检查这种情况——if 在 Erlang 代码中并不经常使用——而是使用模式匹配:
pad_string([D]) ->
[$0,D];
pad_string(S) ->
S.
第一个子句匹配一个单元素列表,并返回一个新列表,其中元素D 前面有$0,这是字符0 的字符常量。第二个子句匹配所有其他参数,只返回传入的任何内容。
这是包含所有更改的完整版本:
-module(demo).
-export([swedish_date/0]).
swedish_date() ->
{YYYY,MM,DD} = date(),
integer_to_list(YYYY) ++
pad_string(integer_to_list(MM)) ++
pad_string(integer_to_list(DD)).
pad_string([D]) ->
[$0,D];
pad_string(S) ->
S.
但更简单的方法是使用the io_lib:format/2 function 直接格式化所需的字符串:
swedish_date() ->
io_lib:format("~w~2..0w~2..0w", tuple_to_list(date())).
首先,请注意,我们将重新调用tuple_to_list(date())。这是因为io_lib:format/2 的第二个参数必须是一个列表。它的第一个参数是一个格式字符串,在我们的例子中表示期望三个参数,将每个参数格式化为一个 Erlang 术语,并将第二个和第三个参数格式化为宽度为 2 和 0 填充。
但还有一步需要解决,因为如果我们运行io_lib:format/2 版本,我们会得到:
1> demo:swedish_date().
["2015",["0",56],"29"]
哇,那是什么?它只是一个深度列表,其中列表的每个元素本身就是一个列表。为了得到我们想要的格式,我们可以展平这个列表:
swedish_date() ->
lists:flatten(io_lib:format("~w~2..0w~2..0w", tuple_to_list(date()))).
执行这个版本给了我们想要的东西:
2> demo:swedish_date().
"20150829"
在下面找到代码的最终完整版本。
-module(demo).
-export([swedish_date/0]).
swedish_date() ->
lists:flatten(io_lib:format("~w~2..0w~2..0w", tuple_to_list(date()))).
更新:@Pascal cmets 应该将年份打印为 2 位而不是 4。我们可以通过列表解析传递日期列表来实现这一点:
swedish_date() ->
DateVals = [D rem 100 || D <- tuple_to_list(date())],
lists:flatten(io_lib:format("~w~2..0w~2..0w", DateVals)).
这会将rem 余数运算符应用于tuple_to_list(date()) 返回的每个列表元素。每月和每天都不需要该操作,但我认为它比提取年份并单独处理要干净。结果:
3> demo:swedish_date().
"150829"