在 Python/Java/Golang 语言的背景下,import 与 use 也让我感到困惑。这将通过一些声明性语言示例来解释代码重用机制。
进口
简而言之,在 Elixir 中,您不需要导入模块。所有公共函数都可以通过完全限定的 MODULE.FUNCTION 语法访问:
iex()> Integer.mod(5, 2)
1
iex()> String.trim(" Hello Elixir ")
"Hello Elixir"
在 Python/Java/Golang 中,您需要 import MODULE 才能使用该 MODULE 中的函数,例如 Python
In []: import math
In []: math.sqrt(100)
Out[]: 10.0
那么,Elixir 中的import 的作用可能会让你大吃一惊:
每当我们想轻松访问其他模块的函数或宏而不使用完全限定名称时,我们都会使用 import
https://elixir-lang.org/getting-started/alias-require-and-import.html#import
所以如果你想输入sqrt而不是Integer.sqrt,trim而不是String.trim,import会有所帮助
iex()> import Integer
Integer
iex()> sqrt(100)
10.0
iex()> import String
String
iex()> trim(" Hello Elixir ")
"Hello Elixir"
这可能会导致阅读代码时出现问题,并且当名称冲突时,Erlang(影响 Elixir 的语言)中为 not recommended。但是 Elixir 中没有这样的约定,您可以自行承担使用它的风险。
在Python中,同样的效果可以通过:
from math import *
并且它只推荐使用in some special scenarios / 交互模式 - 用于更短/更快的输入。
使用和要求
use/require 的不同之处在于它们与“宏”相关——这是 Python/Java/Golang... 系列中不存在的概念。
你不需要import一个模块来使用它的功能,但是你需要require一个模块来使用它的宏:
iex()> Integer.mod(5, 3) # mod is a function
2
iex()> Integer.is_even(42)
** (CompileError) iex:3: you must require Integer before invoking the macro Integer.is_even/1
(elixir) src/elixir_dispatch.erl:97: :elixir_dispatch.dispatch_require/6
iex()> require Integer
Integer
iex()> Integer.is_even(42) # is_even is a macro
true
虽然is_even可以写成普通函数,但它是一个宏,因为:
在 Elixir 中,Integer.is_odd/1 被定义为宏,因此可以用作守卫。
https://elixir-lang.org/getting-started/alias-require-and-import.html#require
use,摘自 Elixir 文档:
use 需要给定的模块,然后在其上调用__using__/1 回调,允许模块将一些代码注入当前上下文。
defmodule Example do
use Feature, option: :value
end
编译成
defmodule Example do
require Feature
Feature.__using__(option: :value)
end
https://elixir-lang.org/getting-started/alias-require-and-import.html#use
所以写use X和写是一样的
require X
X.__using__()
use/2is a macro,宏会帮你把代码转换成其他代码。
你会想use MODULE当你:
- 想要访问它的宏 (
require)
- AND 执行
MODULE.__using__()
在 Elixir 1.5 上测试