Elixir 列表解释为 char 列表

Posted

技术标签:

【中文标题】Elixir 列表解释为 char 列表【英文标题】:Elixir lists interpreted as char lists 【发布时间】:2015-07-14 07:09:29 【问题描述】:

我刚刚开始使用 Elixir。我正在使用 ExUnit 为我自己实现的简单 Enumerable 函数编写一些测试,而不使用标准 Enum 模块。

在我的测试中,我发现每当我引用列表[7, 8, 9] 时,一旦它打印在标准输出中,我就会看到字符列表'\a\b\t'。为什么会出现这种情况?

【问题讨论】:

请努力接受下面的答案。这个答案现在经常被引用,它应该在左侧有一个绿色的检查。 我认为这不会发生 (Last seen Jun 28 '15 at 2:56)。 【参考方案1】:

Elixir 有两种字符串:二进制(双引号)和字符列表(单引号)。后一种变体继承自 Erlang,内部表示为整数列表,映射到字符串的代码点。

当您使用inspectIO.inspect 之类的函数时,Elixir 会尝试智能并将整数列表格式化为字符串以便于阅读。但是,在某些情况下,您最终会得到一个无意义的字符串,因为您列表中的所有整数恰好都是有效的代码点。例如,字符 A 到 Z 表示为 ASCII 中的整数 65 到 90。

iex> IO.inspect [65, 66, 67]
'ABC'

如果您想打印原始列表,可以使用charlists: :as_lists 选项。要查看完整的选项列表,请打开 iex 并输入 h Inspect.Opts

iex> IO.inspect [65, 66, 67], charlists: :as_lists
[65, 66, 67]

使用 Elixir char_lists: false。

顺便说一句,这不是 Elixir 向您隐藏底层构建块的唯一情况,二进制文件(双引号字符串)和结构也会发生这种情况。

更深层次的原因是 Elixir 和 Erlang 没有用户定义的类型,因此无法区分列表和单引号字符串,因为两者都只是列表。但是,这在其他情况下也可能是一种优势。例如,它允许我们简单地序列化 Elixir 和 Erlang 中的任何数据结构,因为它只能从语言附带的基本构建块构建。

【讨论】:

谢谢@Patrick Oscity,这就是我要找的解释。 @Patrick Oscity:只是出于好奇,Elixir 没有“用户定义的类型”从什么意义上说?如果你真的需要它们,你可以使用 @type absolute_string :: :definitely_string, String.t 与 e.g. 有什么根本区别吗?哈斯克尔? @MiroslavPrymek 不同之处在于类型只是 Elixir 中的注释,而不是语言的“真正”部分。您可以使用它们进行静态分析,但实际类型是动态的,忽略注释。因此,可以将类型创建为注解,但在程序运行时无法引用这些类型。例如,您不能编写一个接受任何值并返回其类型的函数。在运行时,所有值似乎都是由基本类型组成的。另见elixir-lang.org/getting-started/typespecs-and-behaviours.html 然而,类型的定义也不那么严格,这可能会让来自 Haskell 的人感到震惊 ;-)。我现在真的找不到合适的词,但我会尝试的。您可能想阅读第 9 章“旁白——什么是类型?”来自 Dave Thomas 的书Programming Elixir。本质上,他说虽然每个值都只是由原始类型组成,但您可以通过定义期望值遵守特定方案的函数来获得准类型。例如,二维空间中的坐标可以用一个二元元组来表示。 这些函数然后被分组到模块中,这些模块将用于处理类型的所有函数保持在一起。尽管如此,没有办法反省这种类型的打字。这一切都发生在概念层面,而不是建立在语言内严格的类型规则之上。你会发现这有时会导致奇怪的错误,但我发现这并不是人们一开始想象的问题。【参考方案2】:

虽然@Patrick 的回答绝对正确,但您也可以将IEx 配置为始终将charlists 显示为常规列表,而不是每次手动调用inspect

iex> IEx.configure(inspect: [charlists: :as_lists])
# => :ok

iex> [65, 66, 67]
# => [65, 66, 67]

iex> 'ABC'
# => [65, 66, 67]

这是full list of supported options

【讨论】:

【参考方案3】:

要为您的环境禁用此行为,create a ~/.iex.exs file 始终应用配置:

# .iex.exs
IEx.configure(inspect: [charlists: :as_lists])

这避免了每次都需要为inspect 提供选项或手动运行IEx.configure

如果您想覆盖特定项目的全局设置,您也可以使用separate .iex scripts per directory。

【讨论】:

以上是关于Elixir 列表解释为 char 列表的主要内容,如果未能解决你的问题,请参考以下文章

TypeError:“列表”对象不能解释为整数

char列表上的SML模式匹配

如何将布尔值列表转换为单个 int,其中每个布尔值都被解释为位?

Elixir/Erlang:变量列表与许多其他列表合并时出错

Elixir Enum vs Erlang列表

Elixir / JInterface - 从 Java 将字符串列表发送回 elixir