查看源代码 兼容性和弃用

Elixir 的版本号遵循 vMAJOR.MINOR.PATCH 的模式。

Elixir 目前处于 v1 的主版本。每 6 个月会发布一个新的向后兼容的次要版本。补丁版本没有固定的发布计划,只有在修复 bug 或安全漏洞时才会发布。

Elixir 只会对最新的次要分支应用 bug 修复。安全补丁适用于最近 5 个次要分支。

Elixir 版本支持
1.16bug 修复和安全补丁
1.15仅安全补丁
1.14仅安全补丁
1.13仅安全补丁
1.12仅安全补丁

新版本会在只读的 公告邮件列表 中发布。所有安全版本 都会被标记为 [security]

目前没有计划发布 v2 主版本。

非主版本 Elixir 版本之间的兼容性

Elixir 的次要版本和补丁版本是向后兼容的:在某个特定版本中定义良好的行为和文档化的 API 将在未来的版本中继续起作用。

虽然我们预计绝大多数程序在未来会保持兼容,但无法保证未来的任何更改都不会导致程序中断。在一些不太可能的情况下,我们可能会引入会破坏现有代码的更改。

  • 安全:实现中可能会出现安全问题,其解决方案需要向后不兼容的更改。我们保留解决此类安全问题的权利。

  • bug:如果 API 的行为不符合预期,依赖于错误行为的程序在修复 bug 后可能会中断。我们保留修复此类 bug 的权利。

  • 编译器前端:可能会对编译器进行改进,引入对模糊模式的新警告并提供更详细的错误消息。这些可能会导致编译错误(在使用 --warning-as-errors 运行时)或在断言特定错误消息时导致工具故障(虽然应该避免这种情况)。我们保留进行此类改进的权利。

  • 导入:可能会向 Kernel 模块添加新函数,该模块是自动导入的。它们可能会与您模块中定义的本地函数发生冲突。可以使用 import Kernel, except: [...](其中包含您不想从 Kernel 导入的所有函数的列表)以向后兼容的方式解决冲突。我们保留进行此类添加的权利。

为了在不引入破坏性更改的情况下继续发展语言,Elixir 将依靠弃用机制来降低某些实践的使用并推广新的实践。我们的弃用策略在 “弃用”部分 中概述。

上述兼容性保证的唯一例外是实验性功能,这些功能将被明确标记为实验性,并且在稳定之前不提供任何兼容性保证。

Elixir 与 Erlang/OTP 之间的兼容性

Erlang/OTP 的版本控制独立于 Elixir 的版本控制。Erlang 每年都会发布一个新的主版本。我们的目标是在 Elixir 发布时支持最新的三个 Erlang 主版本。兼容性表如下所示。

Elixir 版本支持的 Erlang/OTP 版本
1.1624 - 26
1.1524 - 26
1.1423 - 25(以及 v1.14.5 中的 Erlang/OTP 26)
1.1322 - 24(以及 v1.13.4 中的 Erlang/OTP 25)
1.1222 - 24
1.1121 - 23(以及 v1.11.4 中的 Erlang/OTP 24)
1.1021 - 22(以及 v1.10.3 中的 Erlang/OTP 23)
1.920 - 22
1.820 - 22
1.719 - 22
1.619 - 20(以及 v1.6.6 中的 Erlang/OTP 21)
1.518 - 20
1.418 - 19(以及 v1.4.5 中的 Erlang/OTP 20)
1.318 - 19
1.218 - 18(以及 v1.2.6 中的 Erlang/OTP 19)
1.117 - 18
1.017 - 17(以及 v1.0.5 中的 Erlang/OTP 18)

Elixir 可能会在补丁版本中添加对新 Erlang/OTP 版本的兼容性,例如 v1.4.5 中对 Erlang/OTP 20 的支持。这些版本是为了方便而发布的,通常包含 Elixir 无需错误运行所需的最小更改(如果有)。只有下一个次要版本,在本例中为 v1.5.0,才会有效地利用最新 Erlang/OTP 版本提供的功能。

弃用

策略

Elixir 的弃用机制分为 3 个步骤。

  1. 功能被软弃用。这意味着 CHANGELOG 和文档必须将功能列为已弃用,但运行代码时不会发出实际的警告。软弃用功能不是强制性的。

  2. 功能被实际弃用,在使用时会发出警告。这也被称为硬弃用。为了弃用功能,建议的替代方案必须存在至少三个次要版本。例如,Enum.uniq/2 在 Elixir v1.1 中被软弃用,建议使用 Enum.uniq_by/2。这意味着 Elixir v1.4 或更高版本才会发出弃用警告。

  3. 功能被移除。这只能在主版本中发生。这意味着 Elixir v1.x 中的已弃用功能只能在 Elixir v2.x 中移除。

弃用表

第一列是功能被硬弃用的版本。第二列简要描述了已弃用的功能,第三列解释了替代方案以及替代方案可用的版本。

版本已弃用的功能替代方案(自版本起可用)
v1.16~R/.../~r/.../ (v1.0)
v1.16Enum.slice/2 中具有负步长的范围范围中的显式步长 (v1.11)
v1.16String.slice/2 中具有负步长的范围范围中的显式步长 (v1.11)
v1.15Calendar.ISO.day_of_week/3Calendar.ISO.day_of_week/4 (v1.11)
v1.15Exception.exception?/1Kernel.is_exception/1 (v1.11)
v1.15Regex.regex?/1Kernel.is_struct/2 (Kernel.is_struct(term, Regex)) (v1.11)
v1.15Logger.warn/2Logger.warning/2 (v1.11)
v1.14use Bitwiseimport Bitwise (v1.0)
v1.14~~~/1bnot/2 (v1.0)
v1.14Application.get_env/3 和类似函数在模块体中Application.compile_env/3 (v1.10)
v1.14String.starts_with?/2 中的编译模式传递字符串列表 (v1.0)
v1.14Mix.Tasks.Xref.calls/1编译跟踪器(在 Code 中概述) (v1.10)
v1.14$levelpad 在 Logger 中
v1.14<|> 作为自定义运算符另一个自定义运算符 (v1.0)
v1.13!!= 在版本要求中~>>= (v1.0)
v1.13Mix.ConfigConfig (v1.9)
v1.13:strip_beam 配置到 mix escript.build:strip_beams (v1.9)
v1.13Macro.to_string/2Macro.to_string/1 (v1.0)
v1.13System.get_pid/0System.pid/0 (v1.9)
v1.12^^^/2bxor/2 (v1.0)
v1.12@foo() 用于读取模块属性删除括号 (v1.0)
v1.12use EEx.Engine明确委托给 EEx.Engine (v1.0)
v1.12:xref 编译器在 Mix 中无(它现在始终作为编译器的一部分运行)
v1.11Mix.Project.compile/2Mix.Task.run("compile", args) (v1.0)
v1.11Supervisor.Spec.worker/3Supervisor.Spec.supervisor/3Supervisor 中概述的新子进程规范 (v1.5)
v1.11Supervisor.start_child/2Supervisor.terminate_child/2DynamicSupervisor (v1.6)
v1.11System.stacktrace/1__STACKTRACE__try/catch/rescue 中 (v1.7)
v1.10Code.ensure_compiled?/1Code.ensure_compiled/1 (v1.0)
v1.10Code.load_file/2Code.require_file/2 (v1.0) 或 Code.compile_file/2 (v1.7)
v1.10Code.loaded_files/0Code.required_files/0 (v1.7)
v1.10Code.unload_file/1Code.unrequire_files/1 (v1.7)
v1.10Logger.log/2 传递非字符数据使用 to_string/1 显式转换为字符串 (v1.0)
v1.10:compile_time_purge_levelLogger 应用程序环境中:compile_time_purge_matchingLogger 应用程序环境中 (v1.7)
v1.10Supervisor.Spec.supervise/2Supervisor 中概述的新子进程规范 (v1.5)
v1.10:simple_one_for_one 策略在 SupervisorDynamicSupervisor (v1.6)
v1.10:restart:shutdownTask.Supervisor.start_link/1:restart:shutdownTask.Supervisor.start_child/3 中 (v1.6)
v1.9Map.drop/2Map.split/2Map.take/2 中的可枚举键预先对第二个参数调用 Enum.to_list/1 (v1.0)
v1.9Mix.Project.load_paths/1Mix.Project.compile_path/1 (v1.0)
v1.9String.replace/4 传递 :insert_replaced使用 :binary.replace/4 (v1.0)
v1.8Collectable.into/1 传递非空列表++/2Keyword.merge/2 (v1.0)
v1.8for/1 中的 :into 传递非空列表++/2Keyword.merge/2 (v1.0)
v1.8Enum.into/2 传递非空列表++/2Keyword.merge/2 (v1.0)
v1.8时间单位使用复数形式,例如::seconds:milliseconds使用单数形式,例如::second:millisecond 等 (v1.4)
v1.8Inspect.Algebra.surround/3Inspect.Algebra.concat/2Inspect.Algebra.nest/2 (v1.0)
v1.8Inspect.Algebra.surround_many/6Inspect.Algebra.container_doc/6 (v1.6)
v1.9--detachedKernel.CLI--erl "-detached" (v1.0)
v1.8Kernel.ParallelCompiler.files/2Kernel.ParallelCompiler.compile/2 (v1.6)
v1.8Kernel.ParallelCompiler.files_to_path/2Kernel.ParallelCompiler.compile_to_path/2 (v1.6)
v1.8Kernel.ParallelRequire.files/2Kernel.ParallelCompiler.require/2 (v1.6)
v1.8Mix.Compilers.Erlang.compile/6 的回调中返回 {:ok, contents}:error返回 {:ok, contents, warnings}{:error, errors, warnings} (v1.6)
v1.8System.cwd/0System.cwd!/0File.cwd/0File.cwd!/0 (v1.0)
v1.7Code.get_docs/2Code.fetch_docs/1 (v1.7)
v1.7Enum.chunk/2,3,4Enum.chunk_every/2Enum.chunk_every/3,4 (v1.5)
v1.7GenServer 回调中调用 super/1在不调用 super/1 的情况下显式实现行为 (v1.0)
v1.7不在右边left not in right (v1.5)
v1.7Registry.start_link/3Registry.start_link/1 (v1.5)
v1.7Stream.chunk/2,3,4Stream.chunk_every/2Stream.chunk_every/3,4 (v1.5)
v1.6Enum.partition/2Enum.split_with/2 (v1.4)
v1.6Macro.unescape_tokens/1,2使用 Enum.map/2 遍历参数 (v1.0)
v1.6Module.add_doc/6@doc 模块属性 (v1.0)
v1.6Range.range?/1_.._ 模式匹配 (v1.0)
v1.5() 代表 nilnil (v1.0)
v1.5char_list/0 类型charlist/0 类型 (v1.3)
v1.5Atom.to_char_list/1Atom.to_charlist/1 (v1.3)
v1.5Enum.filter_map/3Enum.filter/2 + Enum.map/2for/1 推导式 (v1.0)
v1.5Float.to_char_list/1Float.to_charlist/1 (v1.3)
v1.5GenEvent 模块SupervisorGenServer (v1.0);<br/>GenStage (v1.3);<br/>:gen_event (Erlang/OTP 17)
v1.5<%=EEx 中的中间和结束表达式中使用 <% (<%= 仅允许在开始表达式中) (v1.0)
v1.5:as_char_lists 值在 Inspect.Opts.t/0 类型中:as_charlists 值 (v1.3)
v1.5:char_lists 键在 Inspect.Opts.t/0 类型中:charlists 键 (v1.3)
v1.5Integer.to_char_list/1,2Integer.to_charlist/1Integer.to_charlist/2 (v1.3)
v1.5to_char_list/1to_charlist/1 (v1.3)
v1.5List.Chars.to_char_list/1List.Chars.to_charlist/1 (v1.3)
v1.5@compile {:parse_transform, _}Module
v1.5Stream.filter_map/3Stream.filter/2 + Stream.map/2 (v1.0)
v1.5String.ljust/3String.rjust/3使用 String.pad_leading/3String.pad_trailing/3 以及二进制填充 (v1.3)
v1.5String.lstrip/1String.rstrip/1String.trim_leading/1String.trim_trailing/1 (v1.3)
v1.5String.lstrip/2String.rstrip/2使用 String.trim_leading/2String.trim_trailing/2 以及二进制作为第二个参数 (v1.3)
v1.5String.strip/1String.strip/2String.trim/1String.trim/2 (v1.3)
v1.5String.to_char_list/1String.to_charlist/1 (v1.3)
v1.4-> 之后没有表达式的匿名函数使用表达式或显式返回 nil (v1.0)
v1.4支持使 私有函数 可重写使用 公共函数 (v1.0)
v1.4用作函数调用的变量使用圆括号 (v1.0)
v1.4Access.key/1Access.key/2 (v1.3)
v1.4Behaviour 模块@callback 模块属性 (v1.0)
v1.4Enum.uniq/2Enum.uniq_by/2 (v1.2)
v1.4Float.to_char_list/2:erlang.float_to_list/2 (Erlang/OTP 17)
v1.4Float.to_string/2:erlang.float_to_binary/2 (Erlang/OTP 17)
v1.4HashDict 模块Map (v1.2)
v1.4HashSet 模块MapSet (v1.1)
v1.4IEx.Helpers.import_file/2IEx.Helpers.import_file_if_available/1 (v1.3)
v1.4Mix.Utils.camelize/1Macro.camelize/1 (v1.2)
v1.4Mix.Utils.underscore/1Macro.underscore/1 (v1.2)
v1.4OptionParser 中的多个字母别名使用单个字母别名 (v1.0)
v1.4Set 模块MapSet (v1.1)
v1.4Stream.uniq/2Stream.uniq_by/2 (v1.2)
v1.3\x{X*} 在字符串/标识/字符列表中\uXXXX\u{X*} (v1.1)
v1.3Dict 模块Keyword (v1.0) 或 Map (v1.2)
v1.3:append_first 选项在 defdelegate/2显式定义函数 (v1.0)
v1.3Enum.group_by/3 中作为第二个参数的映射/字典Enum.reduce/3 (v1.0)
v1.3Keyword.size/1length/1 (v1.0)
v1.3Map.size/1map_size/1 (v1.0)
v1.3/r 选项在 Regex/U (v1.1)
v1.3Set 行为MapSet 数据结构 (v1.1)
v1.3String.valid_character?/1String.valid?/1 (v1.0)
v1.3Task.find/2使用直接消息匹配 (v1.0)
v1.3URI.decode_query/2 中作为第二个参数的非映射使用映射 (v1.0)
v1.2Dict 行为MapKeyword (v1.0)
v1.1?\xHEX0xHEX (v1.0)
v1.1Access 协议Access 行为 (v1.1)
v1.1as: true | falsealias/2require/2