用途
Gleam Erlang Interop 用于在 Gleam 项目中与 Erlang 生态进行互操作。Gleam 编译为 Erlang,因此可以与庞大的 Erlang 生态无缝互操作。这种互操作让 Gleam 开发者在使用类型安全 Gleam 代码的同时,复用经过实战检验的 Erlang 库,将现代语言特性与数十年生产验证的库结合起来。
互操作机制通过外部函数调用 Erlang 代码,Gleam 的类型系统在边界处提供安全性。Gleam 可以调用任意 Erlang 函数、使用 Erlang 进程,并与 OTP 行为集成,同时保持类型安全。
该技能涵盖外部函数声明、调用 Erlang 模块、处理 Erlang 类型、使用 Erlang 标准库、NIF 与端口,以及在集成 Erlang 代码时安全类型边界的模式。
主要能力
外部函数声明
外部函数用 Gleam 类型声明 Erlang 函数,为 Erlang 代码提供带类型的接口。示例包括:
- 基本外部函数:
@external(erlang, "erlang", "list_to_binary")声明pub fn list_to_binary(list: List(Int)) -> BitArray。 - 多参数外部函数:
@external(erlang, "string", "concat")声明pub fn string_concat(a: String, b: String) -> String。 - 返回 Result 的外部函数:
@external(erlang, "file", "read_file")声明fn erlang_read_file(path: String) -> Result(BitArray, Dynamic),并包装为返回Result(String, String)的 Gleam 函数。 - 使用 Erlang 类型的外部函数:如
maps:get、maps:put。 - 使用 Erlang timer 模块:
@external(erlang, "timer", "sleep")。 - 使用元组的外部函数:
@external(erlang, "calendar", "local_time")返回嵌套元组。 - 使用 atom 的外部函数:
binary_to_atom、atom_to_binary,并可通过不透明类型创建安全包装。 - 带回调的外部函数:
@external(erlang, "lists", "map")。 - 进程相关外部函数:
erlang:self、erlang:spawn。 - 系统外部函数:
erlang:system_time。
外部声明在 Gleam 类型系统与 Erlang 动态运行时之间架起桥梁。
使用 Erlang 标准库
Gleam 可利用 Erlang 全面的标准库执行各种操作,示例包括:
- crypto 模块:
crypto:hash,用于 sha256、md5。 - random 模块:
rand:uniform,用于随机浮点数、随机整数、随机选择。 - ETS(Erlang Term Storage):
ets:new、ets:insert、ets:lookup,用于创建缓存。 - 通过 Erlang httpc 的 HTTP 客户端:
httpc:request。 - 通过 jiffy 库的 JSON:
jiffy:encode、jiffy:decode。 - OS 模块:
os:getenv、os:cmd。 - 代码加载:
code:ensure_loaded。
Erlang 标准库为常见操作提供经过生产验证的功能。
处理 Erlang 类型
Gleam 的 Dynamic 类型支持与 Erlang 动态类型系统安全互操作,示例包括:
- Dynamic 值处理:使用
dynamic.string、dynamic.int判断类型。 - 解码 Erlang 元组:
dynamic.tuple2。 - 解码 Erlang 列表:
dynamic.list。 - 复杂 Erlang 项解码器:使用
dynamic.decode3、dynamic.field、dynamic.optional_field构建 Person 解码器。 - 编码为 Erlang 项:
dynamic.from。 - 处理 Erlang record(元组):自定义 record 解码器。
- Proplist(Erlang 键值列表)处理:
proplist_get。 - 通过 dynamic 处理 atom:
decode_atom。 - BitString 操作:
erlang:bit_size。 - Reference 处理:
erlang:make_ref,并用不透明类型包装。
Dynamic 解码器提供从 Erlang 动态类型到 Gleam 静态类型的安全转换。
NIF 与端口
Native Implemented Functions 和端口支持与 C 代码及外部程序集成,示例包括:
- NIF 声明:
@external(erlang, "my_nif_module", "fast_computation")。 - 用于外部程序通信的端口:
erlang:open_port、erlang:port_command、erlang:port_close。 - 使用端口进行外部进程集成(如 Python 集成)。
- NIF 加载模式:
@external(erlang, "my_module", "init")。 - 带消息传递的端口:定义 PortMessage 类型与 port_receiver。
- 异步 NIF 调度:
@external(erlang, "my_nif", "async_computation")。
NIF 提供性能关键的原生代码,端口支持安全的外部进程通信。
OTP 集成
Gleam 与 OTP 行为和监督树无缝集成,示例包括:
- 直接使用 Erlang gen_server:
gen_server:call、gen_server:cast。 - 包装 Erlang gen_server。
- 使用 Erlang supervisor:
supervisor:start_link。 - Application 行为:
application:start、application:stop。 - 使用 Erlang registry:
erlang:register、erlang:whereis。 - 全局注册:
global:register_name。
OTP 集成支持用经过验证的模式构建生产级应用。
使用方式
该技能以外部函数声明为核心机制,通过 @external(erlang, "模块", "函数") 注解将 Erlang 函数暴露为带 Gleam 类型的函数,再在 Gleam 代码中调用。对于返回动态数据的 Erlang 调用,使用 gleam/dynamic 模块的解码器进行类型安全转换。对于进程、OTP、NIF 与端口,同样通过外部函数声明调用相应 Erlang 模块。
适用场景
- 需要在 Gleam 项目中复用 Erlang 库或标准库功能时。
- 需要调用 Erlang 函数、使用 Erlang 进程或与 OTP 行为集成时。
- 需要与 C 代码(NIF)或外部程序(端口)集成时。
- 需要在 Gleam 类型系统与 Erlang 动态运行时之间建立安全边界时。
限制与注意事项
资料中列出了最佳实践与常见陷阱:
最佳实践:
- 用安全接口包装外部函数,处理错误并提供 Gleam 类型。
- 对所有从 Erlang 接收的数据使用 Dynamic 解码器以确保类型安全。
- 记录外部函数行为,因为 Erlang 代码缺少静态类型信息。
- 显式处理所有 Erlang 错误情况,而非假设成功。
- 对没有直接 Gleam 等价物的 Erlang 类型使用不透明类型。
- 彻底测试互操作边界,因为类型不匹配会导致运行时错误。
- 当功能在 Gleam 标准库与 Erlang 中都存在时,优先使用 Gleam 标准库。
- 对可能失败的 Erlang 调用使用 Result 类型,使错误显式化。
- 调用有复杂要求的 Erlang 代码时,在边界处验证数据。
- 将互操作代码隔离在特定模块中,便于维护。
常见陷阱:
- 不处理 Erlang 错误会导致运行时意外崩溃。
- 外部函数类型注解不正确会导致类型混淆。
- 忘记 Dynamic 解码器会绕过 Erlang 边界的类型安全。
- 未经验证就假设 Erlang 返回特定类型会导致崩溃。
- 未使用实际 Erlang 环境测试(资料原文在此处截断)。
关于收费、价格、平台支持等具体信息,资料中暂未提供。