zoukankan      html  css  js  c++  java
  • [Elixir008]Nested Module里的动态函数调用方式

    有时我们需要动态生成一些模块名,然后调用它里面的函数。但是我们常常碰到的却是明明有那个模块,结果还是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.

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

     

  • 相关阅读:
    oracle中查询表是否存在
    asp.net webform/mvc导出Excel通用代码
    分享给大家一个500G.Net ftp资料库
    C# 使用TopShelf实现Windows服务部署
    C#基于Quartz.NET实现任务调度并部署Windows服务
    附加进程找不到w3wp.exe进程解决方案
    在vs2015中使用附加进程的方式调试IIS中的页面
    删除datatable的行后,出现“不能通过已删除的行访问该行的信息”的错误,即DeletedRowInaccessibleException
    C# FTP操作类
    C# vb .net实现发光效果
  • 原文地址:https://www.cnblogs.com/zhongwencool/p/elixir_module_call.html
Copyright © 2011-2022 走看看