有时我们需要动态生成一些模块名,然后调用它里面的函数。但是我们常常碰到的却是明明有那个模块,结果还是raise模块未定义。。。

我们来看看到底怎么回事?

首先我们定义一个函数

iex(1)> defmodule Science.Math do
...(1)> def add(x,y) do
...(1)> x + y
...(1)> end
...(1)> end

当我们正常调用它是,是没有问题的:

iex(2)> Science.Math.add 1,2
3

但是

iex(3)> t= "Science.Math"
"Science.Math"
iex(4)> :"Science.Math".add(1, 2)
** (UndefinedFunctionError) undefined function :"Science.Math".add/2 (module :"Science.Math" is not available):"Science.Math".add(1, 2)

为什么明明有的模块却没找到呢?

因为我们定义的模块其实应该是:"Elixir.Science.Math", 而不是:"Science.Math"

所以我们应该使用

iex(5)> (t|> String.split(".") |> Module.concat).add(1,2)
3

但是Module做String to Atom的转换时用的是:erlang.binary_to_atom(string, :utf8)

如果在运行期间大量调用这个函数可能造成原子数耗尽(erlang的atom是不回收的)

所以我们还可以使用Module.safe_concat/1

iex(5)> (t|> String.split(".") |> Module.safe_concat).add(1,2)
3

safe_concat使用的 :erlang.binary_to_existing_atom(string, :utf8).

这解决了上面这个函数的风险,但是也引入别一个可能,有可能输入的string是一个系统从来没有exist的atom就会crash掉。

如果我们只是想调用"Nested.Foo.Test"模块里面的函数, 还可以再用一种巧妙的方式。

iex(6)> t = "Science.Math"
"Science.Math"
iex(7)> :"Elixir.#{t}".add(1,2)
3

最后一种方法只是试探性的,其实你选择的方案应该是最优 Module.safe_concat,

如果你的需求真的可能输入一个从来没有exist的模块时,你应该使用Module.concat,但是你想一个方法去保证atom不会耗尽。

让我们最后来回顾一下Module最前面的@moduledoc

Provides functions to deal with modules during compilation time.It allows a developer to dynamically add, delete and register attributes,
attach documentation and so forth.After a module is compiled, using many of the functions in this module will
raise errors, since it is out of their scope to inspect runtime data. Most of
the runtime data can be inspected via the __info__(attr) function attached to
each compiled module.

它本来就不是用来解决运行期间的问题的。。。。

转载于:https://www.cnblogs.com/zhongwencool/p/elixir_module_call.html

[Elixir008]Nested Module里的动态函数调用方式相关推荐

  1. 堆/栈/动态存储方式/静态存储方式

    动态存储方式 所谓动态存储方式是指在程序运行期间根据需要进行动态的分配存储空间的方式.动态存储变量是在程序执行过程中,使用它时才分配存储单元, 使用完毕立即释放. 典型的例子是函数的形式参数,在函数定 ...

  2. JavaScript中七种函数调用方式及对应 this 的含义

    http://blog.sina.com.cn/s/blog_621f1e120100rj21.html this 在 JavaScript 开发中占有相当重要的地位,不过很多人对this这个东西都感 ...

  3. C++函数调用方式(_stdcall, _pascal, _cdecl...)总结 收藏

    C++函数调用方式(_stdcall, _pascal, _cdecl...)总结 收藏 __stdcall: _stdcall 调用约定相当于16位动态库中经常使用的PASCAL调用约定.在32位的 ...

  4. 字节对齐和C/C++函数调用方式学习总结(多篇节选)

    字节对齐和C/C++函数调用方式学习总结 created: 04-06-17 last saved: author: ayixidelu 前言: <***软件编程规范>中提到:" ...

  5. C语言试题八十一之利用递归函数调用方式,将所输入的5个字符,相反顺序打印

    1.题目 利用递归函数调用方式,将所输入的5个字符,相反顺序打印 2 .温馨提示 C语言试题汇总里可用于计算机二级C语言笔试.机试.研究生复试中C程序设计科目.帮助C语言学者打好程序基础.C语言基础, ...

  6. 函数调用方式以及this指向

    函数调用方式以及this指向 普通函数:fn(); function fn(){console.log( '普通函数:'+ this);}fn();//普通函数:window 对象的方法 var ob ...

  7. c语言程序中函数调用本身叫什么,在C语言中函数调用方式有什么区别

    在使用VC进行函数定义时,通常会指定该函数调用方式,那么在C语言中函数调用方式有什么区别呢?下面小编找到了一下教程,分享给大家,希望可以帮助到大家. 通常在使用VC进行函数定义时会指定该函数调用方式, ...

  8. 动态存储方式和静态存储方式

    从变量的作用域的角度来观察,变量可以分为全局变量和局部变量: 全局变量都是存放在静态存储区中的.因此它们的生存期是固定的,存在于程序的整个运行过程 局部变量,如果不专门声明存储类别,都是动态地分配存储 ...

  9. 动态存储方式与静态存储方式

    从变量的作用域的角度来观察,变量可以分为全局变量和局部变量: 全局变量都是存放在静态存储区中的.因此它们的生存期是固定的,存在于程序的整个运行过程 局部变量,如果不专门声明存储类别,都是动态地分配存储 ...

最新文章

  1. oracle官网能用的账号,oracle 官方登录账号Oracle的在windows下的安装及使用
  2. Troubleshooting Open Cursor Issues
  3. 移动广告平台到底哪个好?哪个能赚的米米多?
  4. C++实践参考——时间类
  5. CodeForces:643(VK cup)
  6. 持续定义Saas模式云数据仓库+BI
  7. axios vue 回调函数_VUE使用axios调用后台API接口的方法
  8. 【转】JVM 架构解读
  9. Servlet的API(一)
  10. java limit_Java 8 Stream:limit()和skip()之间的区别
  11. 502 proxy error解决方法_老大说,网上这种获取真实IP地址的方法不对,我不信......
  12. Mysql binlog 的写入机制
  13. Axure| 旋转控件或者图片
  14. lol最新聊天服务器断开,lol聊天服务器断开 英雄联盟聊天服务器连不上解决办法...
  15. java程序员怎么创建自己的网站:第一章:总体流程,我崩溃了
  16. 创业型公司,你要不要去?
  17. 什么样的公司程序员待遇好
  18. 使用VS Code 配置 LaTeX 编辑器
  19. 适配器模式 个人理解+JAVA 小例子
  20. 手机如何批量提取视频中的音频

热门文章

  1. liferay 如何 用 国际化
  2. MySQL约束课堂笔记
  3. 编译原理题练习题测试题
  4. leetcode练习(简单总结做过的题)
  5. 如何将两个虚拟机ping通?如何让虚拟机连网?
  6. Java获取泛型T的类型 T.class
  7. 机器学习实战(用Scikit-learn和TensorFlow进行机器学习)(五)
  8. docker镜像、容器以及命令操作
  9. 使用Android studio 运行react-native项目
  10. ogre研究之第一个程序(二)