我如何才能拥有“私有”Erlang模块?

ssgvzors  于 2022-12-08  发布在  Erlang
关注(0)|答案(4)|浏览(137)

我更喜欢处理少于1000行的文件,所以我想把一些Erlang模块分成更小的部分。
有没有一种方法可以在不扩展库的公共API的情况下实现这一点?
我的意思是,任何时候有一个模块,任何用户都可以做module:func_exported_from_the_module。唯一的方法,真正有东西是私人的,我知道是不导出它从任何模块(即使这样,洞可以戳)。
那么,如果技术上没有办法实现我所寻找的,有没有约定呢?例如,Python类中没有private方法,但是约定是在_my_private_method中使用前导_来标记它为private。
我接受的答案可能是,“不,你必须有4K LOC文件。”

blmhpbnm

blmhpbnm1#

最接近约定的是使用edoc标签,如@private@hidden
来自文档:
@hidden
标记函数,使其不会出现在文档中(即使生成了"私有"文档)。对调试/测试函数等有用。内容可用作注解;它将被EDoc忽略。
@private
将函数标记为private(即不是public接口的一部分),这样它就不会出现在普通文档中。(如果生成了"private"文档,则会包含该函数。)仅对导出函数有用,例如spawn的入口点。(非导出函数总是"private"。)内容可以用作注解;它将被EDoc忽略。

ego6inou

ego6inou2#

  • Please note that this answer started as a comment to @legoscia's answer*

Different visibilities for different methods is not currently supported.
The current convention, if you want to call it that way, is to have one (or several) 'facade' my_lib.erl module(s) that export the public API of your library/application. Calling any internal module of the library is playing with fire and should be avoided (call them at your own risk).
There are some very nice features in the BEAM VM that rely on being able to call exported functions from any module, such as

  1. Callbacks (funs/anonymous funs), MFA, erlang:apply/3: The calling code does not need to know anything about the library, just that it's something that needs to be called
  2. Behaviours such as gen_server need the previous point to work
  3. Hot reloading: You can upgrade the bytecode of any module without stopping the VM. The code server inside the VM maintains at most two versions of the bytecode for any module, redirecting external calls (those with the Module: ) to the most recent version and the internal calls to the current version. That's why you may see some ?MODULE: calls in long-running servers, to be able to upgrade the code
    You'd be able to argue that these points'd be available with more fine-grained BEAM-oriented visibility levels, true. But I don't think it would solve anything that's not solved with the facade modules, and it'd complicate other parts of the VM/code a great deal.

Bonus

Something similar applies to records and opaque types, records only exist at compile time, and opaque types only at dialyzer time. Nothing stops you from accessing their internals anywhere, but you'll only find problems if you go that way:

  • You insert a new field in the record, suddenly, all your {record_name,...} = break
  • You use a library that returns an opaque_adt() , you know that it's a list and use like so. The library is upgraded to include the size of the list, so now opaque_adt() is a tuple() and chaos ensues
dy1byipe

dy1byipe3#

只有那些在-export属性中指定的函数对其他模块可见,即“public”函数。所有其他函数都是private。如果您只指定了-compile(export_all),则模块中的所有函数在外部都是可见的。不建议使用-compile(export_all)

7dl7o3gd

7dl7o3gd4#

我不知道Erlang有什么现有的约定,但是为什么不采用Python的约定呢?假设“library-private”函数的前缀是下划线。你需要用单引号将函数名引起来才能做到这一点:

-module(bar).

-export(['_my_private_function'/0]).

'_my_private_function'() ->
    foo.

那么你可以称之为:

> bar:'_my_private_function'().
foo

对我来说,这清楚地传达了我不应该调用这个函数,除非我知道我在做什么。

相关问题