Elixir模块如何初始化带随机常量并调用随机逻辑?
Elixir 模块编译阶段设置随机模块属性的实现方法
完全可以实现强随机的初始化效果,Elixir在模块定义(编译)阶段支持直接调用函数计算模块属性的取值,不需要额外的特殊语法。
首先纠正你示例写法的两个问题:
- 你写的
@word = @words[1]是固定取索引位置为1的元素,本身没有随机性 - Elixir的列表是链表结构,原生不支持
[下标]的直接取值写法,要按位置取元素需要调用Enum.at/3
基础随机实现
如果只是需要从词表里随机选一个值在编译阶段固化,直接调用Elixir内置的Enum.random/1即可,这个函数会在模块编译时执行,结果会作为常量固定在模块属性中:
defmodule MyMod do @words ["test", "hello", "bye"] # 编译时从词表随机选一个值赋值给@word @word Enum.random(@words) def get_word, do: @word end
用这个写法的话,每次重新编译模块,@word都会重新随机取值,编译完成后运行时调用get_word/0会一直拿到同一个编译时确定的值,不会在运行时变化。
自定义复杂随机逻辑
如果需要实现权重随机、规则过滤这类更复杂的随机逻辑,你可以直接在模块内定义私有函数,在给模块属性赋值时调用即可,和普通函数调用没有区别:
defmodule MyMod do # 词表带权重配置 @words [{"test", 1}, {"hello", 3}, {"bye", 2}] @word weighted_random(@words) # 带权重的随机选择逻辑,编译阶段执行 defp weighted_random(words) do words |> Enum.flat_map(fn {word, weight} -> List.duplicate(word, weight) end) |> Enum.random() end def get_word, do: @word end
需要注意一个规则:编译时给模块属性赋值调用的函数,必须定义在调用位置之前,否则编译阶段会找不到对应函数。
运行时随机的实现
如果你不需要值在编译后固定,想要每次调用函数都拿到新的随机值,就不要把随机结果存在模块属性里,直接把随机逻辑写在运行时执行的函数中即可:
defmodule MyMod do @words ["test", "hello", "bye"] # 每次调用都会重新随机取值 def get_word, do: Enum.random(@words) end
内容的提问来源于stack exchange,提问作者Red Baron
相关产品推荐
相关产品推荐

