一个模块里需要太多次export,谁能用宏简化一下

假如定义了一个module
里面有很多函数,这些函数我都需要,所以在模块尾部我需要一个一个export他们,在别的地方使用又要显式import他们。
我想用这样的方法定义函数:

pub function foo()
end

这样我就不用export了,但是没有pub这个关键字,我想问一下有没有办法写一个宏,使得函数定义和export在一条语句里依次执行,这样就可以少写很多代码了

试着写了一个

macro public(ex)
    if ex.head == :function || ex.head == :(=)
        eval(ex)
        if ex.args[1] isa Symbol
            :(export $(ex.args[1]))
        else
            :(export $(ex.args[1].args[1]))
        end
    else
        @error "not a defination of function"
    end
end

Thank you:grinning:

那个,如果我要export模块里的结构体我该怎么重写这个宏??

可以用

ex = Meta.parse("""struct foo 
                   end""")

看一下传入的Expr是怎样构成的,ex.head是什么,找到 foo 对应的位置,写个if判断一下ex.head, 构造一个 :(export foo)

顺便问一下,这个宏在把参数代入时是不是会做一些处理,比如把ex当作一个表达式Expr来处理,而不是纯文本

感谢你的提醒,这个宏照你的参考了一下,做出来了

macro pub(ex)
    eval(ex)
    if ex.head == :struct
        :(export $(ex.args[2]))
    elseif ex.head == :function || ex.head == :(=)
        if ex.args[1] isa Symbol
            :(export $(ex.args[1]))
        else
            :(export $(ex.args[1].args[1]))
        end
    end
end

就是在定义模块时在下面显式导入才能用

module foo
import ..@pub
#code
end

是的,传入的参数是表达式或者符号

好像又出问题了,这个宏好像是在全局作用域定义函数,像这样

那个,我好像找到原因了,这个宏确实是在全局定义函数,而不是模块内部
你看这里,我不用导出就能应用这个函数:

但是如果你全部都要导出,那你为什么要用module呢?module的目的就是控制不要导出啊。

如果是想写inline的export,可以看下InlineExport.jl,这个syntax日后应该会进入Julia里。也就是export可以直接写定义前面,不需要写两遍名字了就。

纯属好奇,不断尝试作死

1 个赞

应该是 eval 的问题,改成 __module__.eval

eval(expr)

Evaluate an expression in the global scope of the containing module. Every Module (except those defined with baremodule) has its own 1-argument definition of eval, which evaluates expressions in that module.

非常感谢,终于解决了

我又改进了一下,加入泛型的struct和function

macro pub(ex)
    __module__.eval(ex)
    #function
    if ex.head == :function || ex.head == :(=)
        if ex.args[1].head == :where
            :(export $(ex.args[1].args[1].args[1]))
        else
            :(export $(ex.args[1].args[1]))
        end
    elseif ex.head == :struct# struct
        if ex.args[2] isa Symbol
            :(export $(ex.args[2]))
        else
            :(export $(ex.args[2].args[1]))
        end
    else
        @error "not a define of struct or function"
    end

end

你并不需要显示地一个一个import这些函数,只需要类似于using Images就可以了

那你有没有考虑过两个模块里有同名,同参数的函数时该怎么办

在那种情况下确实是需要显示导入的,但是这并不意味着你需要显示导入所有名称(包括那些不冲突的)。