HelloWorld 与 Elixir 使用教程

Elixir 是基于 BEAM(Erlang 虚拟机)的函数式并发语言,写 HelloWorld 最直接的两种方式是:在交互式 shell(iex)里即时输出,或创建模块/脚本用 mix/elixirc 编译运行。理解模块、函数、进程与 Mix 工具链,能让你从简单示例自然过渡到并发、测试与发布流程。

HelloWorld 与 Elixir 使用教程

我先把思路讲清楚:为什么学 HelloWorld 要关心这些

费曼法告诉我们:把复杂的东西拆成简单的块再解释。写一个 HelloWorld 看似很简单,但对于 Elixir 来说,关键不在于那句输出语,而在于运行它的环境和工具链——iex(交互式)、脚本、模块、Mix 项目、编译与发布。理解这些,你就能把后续的并发、OTP、测试和部署都串起来。

准备工作:安装与验证

不啰嗦,先确保环境对了。常见做法是通过官方包管理器安装 Erlang,然后安装 Elixir,或者用 asdf 管理版本。安装后,你可以这样快速验证:

  • 验证 Erlang/Elixir:在终端运行 erlelixir –versioniex –version
  • 打开交互式 shell:运行 iex,你就可以即时执行 Elixir 表达式。

常用命令一览(表格)

命令 用途
elixir file.exs 直接运行脚本(不编译到 .beam)
elixirc file.ex 编译 .ex 源文件生成 .beam(Erlang VM 格式)
iex 交互式 shell,适合试验和调试
mix new my_app 创建 Mix 项目骨架
mix test 运行测试
mix release 构建发行包(部署用)

HelloWorld:从最简单到项目化的步骤

1) 在 iex 里即时输出(最快)

打开终端,输入 iex,它会给你一个提示符。然后直接键入:

iex> IO.puts("Hello, world!")

结果会立即打印。这个方式像是在试验台上直接点燃火花,适合验证表达式或库函数。

2) 用脚本文件(.exs)运行

把内容写到一个文件,比如 hello.exs

IO.puts("Hello, world from script!")

运行:elixir hello.exs。这种方式适合小工具、一次性脚本或学习流程。

3) 用模块和函数(更接近真实工程)

当你需要写可重用代码时,应该把逻辑包在模块中。创建 hello.ex

defmodule Hello do
  def world do
    IO.puts("Hello, world from module!")
  end
end

编译并在 iex 中加载:

elixirc hello.ex
iex -S mix
# 或在 iex 中: c("hello.ex"); Hello.world()

注意:elixirc 会生成 .beam 文件,可以被 Erlang VM 直接加载。

4) 使用 Mix 创建项目并运行

真实项目通常使用 Mix 管理。命令:

mix new demo
cd demo
# 在 lib/demo.ex 写模块,或在 lib/demo/application.ex 配置应用

在项目里,你可以运行 mix run -e ‘Demo.hello()’ 来执行指定函数,或者 iex -S mix 进入带项目依赖的交互式环境。

深入一点:Elixir 的核心概念(用最简单的话解释)

把 Elixir 想象成一套工具箱,工具箱里有模块、函数、进程、消息、以及一把叫 BEAM 的坚固发动机。你写模块和函数来描述计算,把并发问题交给进程和消息来解决,Mix 帮你组织和发布。下面逐个拆开说。

模块与函数

  • 模块(Module):就是命名空间,把函数组织起来。用 defmodule 定义。
  • 函数(Function):通过 def 定义,可以有不同的参数模式(重载式)和守卫。

示例(带参数匹配):

defmodule Greeter do
  def hello("world"), do: IO.puts("Hello, world!")
  def hello(name),     do: IO.puts("Hello, " <> name)
end

模式匹配(pattern matching)和不可变性

模式匹配不是等号的替代品,而是解构数据、提取值的主要方式。变量一旦绑定,在同一作用域内不可变——这让并发更安全,更容易推理。

{a, b} = {1, 2}
# a = 1, b = 2

进程与消息(并发基础)

Elixir 的“轻量级进程”非常便宜,可以成千上万地并发运行。进程通过消息传递通信,没有共享内存,从而避免很多并发陷阱。

spawn(fn -> IO.puts("I am a process") end)

更实用的是用 GenServer 去封装状态和行为,这属于 OTP 的范畴。

把 HelloWorld 做成一个小服务(举例)

好,我们来做个小 demo:用 GenServer 管理一个简单的问候计数器,每次调用都会返回问候消息并增加计数。这样可以把“HelloWorld”从一句输出变成一个带状态的服务。

代码示例(简洁版 GenServer)

defmodule HelloCounter do
  use GenServer

  # Client API
  def start_link(initial \\ 0), do: GenServer.start_link(__MODULE__, initial, name: __MODULE__)
  def greet(), do: GenServer.call(__MODULE__, :greet)

  # Server callbacks
  def init(count), do: {:ok, count}
  def handle_call(:greet, _from, count) do
    msg = "Hello! You've been greeted #{count} times."
    {:reply, msg, count + 1}
  end
end

# 启动与调用(在 iex -S mix 中)
{:ok, _} = HelloCounter.start_link(1)
HelloCounter.greet()

看,这比简单打印丰富得多:有状态、可测试、可扩展。

测试、工具与调试

写完代码别忘了测试。Elixir 默认集成 ExUnit。简单示例:

defmodule HelloTest do
  use ExUnit.Case
  test "greet increments" do
    {:ok, _} = HelloCounter.start_link(0)
    assert HelloCounter.greet() =~ "greeted 0"
    assert HelloCounter.greet() =~ "greeted 1"
  end
end

调试时常用:

  • iex.pry / IEx.pry():可以在运行时进入调试交互式会话(需要在 mix.exs 启用 :debug 或使用 require IEx)。
  • Logger:Elixir 的日志工具,支持不同等级和后端。

部署与发布(简单说明)

生产部署通常用 Mix Releases(自带)或者 Distillery(较老),思路是生成一个包含 Erlang VM、应用和依赖的可运行包。基本流程:

  • 在 mix.exs 中配置 release。
  • 运行 mix release 生成可部署目录。
  • 在目标机器上解压并使用生成的脚本来启动/停止。

这就是为什么早期我们强调理解 Mix:它把创建、测试、打包、发布串成一条流水线。

性能与常见陷阱(实用提醒)

  • 不要把 CPU 密集型任务放到 BEAM 进程里:BEAM 擅长并发 I/O 与大量轻量任务,但密集计算会阻塞调度器,应该用 NIF、C 驱动或独立服务。
  • 避免全局可变状态:借助 Agent/GenServer 管理状态,而不是用全局可变结构。
  • 监控和观察:在生产环境开启 telemetry、Prometheus 导出或其他 APM,以便发现瓶颈。
  • 理解 supervision tree:用监督树管理进程生命周期,使系统有自愈能力。

小贴士:把学习路径拆成小步

  • 第一周:熟悉 iex、基本语法、模块与函数、pattern matching。
  • 第二周:学 Mix,写小项目,增加测试(ExUnit)。
  • 第三周:探索并发(spawn、Tasks、GenServer),实现一个小服务。
  • 第四周:学习 supervision、release,尝试打包并在另一台机器上运行。

按这样的节奏,你会发现从一句 HelloWorld 到能上线的服务,路径并不长,关键是每一步都弄懂“为什么”。

常见问题快速解答

  • Q:什么时候用 .exs 与 .ex?

    A:脚本(.exs)适合一次性任务或快速试验;模块与库用 .ex(可编译成 .beam),用于生产与测试。

  • Q:如何在项目里使用第三方依赖?

    A:在 mix.exs 的 deps 函数里声明依赖,然后 run mix deps.get

  • Q:如何优雅地终止 GenServer?

    A:使用 GenServer.stop/3 或让 supervisor 管理其重启策略。

参考与继续学习的方向(简单列举)

  • Elixir 官方文档与 Getting Started;
  • 《Programming Elixir》以及 José Valim 的讲座/文章;
  • 学习 OTP 原理(GenServer、Supervisor、Application);
  • 实践:把一个小服务从本地部署到远端,观察日志与性能。

行文到这里,我自己也有点想再跑一个例子来确认行为,嗯……不过基本思路就是这样:先从 iex 和脚本感觉语言,再把功能包装到模块和 Mix 项目里,慢慢引入并发、测试与发布。一步一步来,别急着全部学完再动手,写第一个能跑的 HelloWorld,是最实在的开始。

返回首页