Elixir递归匿名函数报错:2nd argument: not valid character data
Elixir递归匿名函数IO输出报错的解决办法
错误原因
你碰到的“2nd argument: not valid character data (an iodata term)”错误,本质是IO.puts/1的参数类型不匹配:IO.puts仅支持输出字符数据(字符串、字符列表等文本类型),但你的calcTipsAndTotals函数返回的是嵌套的浮点数列表([计算出的小费列表, 总金额列表]),这种数据结构无法被IO.puts直接解析。
快速修复方案
用inspect/1函数把递归返回的列表转换成可读字符串,再传入IO.puts:
IO.puts( inspect(calcTipsAndTotals.(0, [], [], calcTipsAndTotals)) )
修改后运行就能正确打印出两个列表的内容。
更符合Elixir风格的写法
原代码用索引+递归的写法虽然能跑,但不符合Elixir的惯用思维,而且每次调用length(bills)和Enum.at都是O(n)操作,效率较低。推荐直接遍历列表生成结果:
方式一:用Enum.map分别生成小费和总金额
calc_tip = fn bill -> if bill in 50..300, do: bill * 0.15, else: bill * 0.2 end bills = [22, 295, 176, 440, 37, 105, 10, 1100, 86, 52] tips = Enum.map(bills, calc_tip) totals = Enum.zip_with(bills, tips, &+/2) # 格式化输出 IO.puts("小费列表:#{inspect(tips)}") IO.puts("总金额列表:#{inspect(totals)}")
方式二:用Enum.reduce一次生成两个列表
calc_tip = fn bill -> if bill in 50..300, do: bill * 0.15, else: bill * 0.2 end bills = [22, 295, 176, 440, 37, 105, 10, 1100, 86, 52] {tips, totals} = Enum.reduce(bills, {[], []}, fn bill, {tips_acc, totals_acc} -> tip = calc_tip.(bill) {[tip | tips_acc], [bill + tip | totals_acc]} end) |> then(fn {t, ts} -> {Enum.reverse(t), Enum.reverse(ts)} end) IO.puts("小费列表:#{inspect(tips)}") IO.puts("总金额列表:#{inspect(totals)}")
内容的提问来源于stack exchange,提问作者Djordje Vuckovic
相关产品推荐
相关产品推荐

