erlang 中的命名空间和记录

发布于 2024-10-08 16:33:23 字数 495 浏览 8 评论 0原文

Erlang 显然有一个命名空间的概念,我们每天都会使用诸如 application:start() 这样的东西。

我想知道是否有记录命名空间之类的东西。在我的应用程序中,我定义了记录用户。一切都很好,直到我需要包含来自 RabbitMQ 的 rabbit.hrl,它也定义了 user,这与我的冲突。

在线搜索并没有得到太多解决这个问题的结果。我考虑过重命名我的用户记录并在其前面添加一些前缀,例如“myapp_user”。这将解决这个特定问题,直到我怀疑我遇到了另一个冲突,比如我的记录“会话”。

我在这里有什么选择?向我的所有记录添加前缀 myapp_ 是一个好习惯,还是对包含记录的命名空间有真正的支持,但我只是找不到它?

编辑:谢谢大家的回答。我了解到的是,这些记录是全球性的。接受的答案已经说得很清楚了。正如我所期望的,我将向我的所有记录添加前缀。

Erlang obviously has a notion of namespace, we use things like application:start() every day.

I would like to know if there is such a thing as namespace for records. In my application I have defined record user. Everything was fine until I needed to include rabbit.hrl from RabbitMQ which also defines user, which is conflicting with mine.

Online search didn't yield much to resolve this. I have considered renaming my user record and prefixing it with something, say "myapp_user". This will fix this particular issue, until I suspect I hit another conflict say with my record "session".

What are my options here? Is adding a prefix myapp_ to all my records a good practice, or is there a real support for namespaces with records and I am just not finding it?

EDIT: Thank you everyone for your answers. What I've learned is that the records are global. The accepted answer made it very clear. I will go with adding prefixes to all my records, as I have expected.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

所有深爱都是秘密 2024-10-15 16:33:23

我认为 Erlang 没有任何命名空间。模块是全局的(除了非常不受欢迎的语言扩展),名称是全局的(无论是节点还是集群),pid 是全局的,端口是全局的,引用是全局的,等等。

一切都是平淡的。因此,Erlang 中的命名空间是按照惯例而不是任何其他方式完成的。这就是为什么您使用 _app_sup 等作为模块名称。注册流程也可能遵循该模式以及 ETS 表等。

但是,您应该注意,记录本身并不是全局事物:正如只是我的正确意见所指出的它,记录只是编译器对元组的技巧。因此,它们对于模块定义来说是本地的。模块外部的任何人都不会看到记录,除非他们还包含记录定义(通过复制它或使用头文件,后者是最好的方法)。

现在我可以说,因为您需要包含 .hrl 文件并在每个模块的基础上记录定义,所以不存在命名空间记录之类的东西;它们在模块中的作用域相当有限,就像变量一样。没有理由给它们命名:只需包含正确的名称即可。

当然,可能存在这样的情况:您包含来自两个模块的记录定义,并且两个记录具有相同的名称。如果发生这种情况,可能需要使用前缀重命名记录,但根据我的经验,这种情况相当罕见。

请注意,将记录公开给其他模块通常也是一个坏主意。这样做的问题之一是所有依赖于您的模块现在都包含其 .hrl 文件。如果您的模块随后更改了记录定义,您将必须重新编译依赖于它的所有其他模块。更好的做法应该是实现与数据交互的函数。请注意, get(Key, Struct) 并不总是一个好主意。如果您可以选择有意义的名称(年龄、名字、孩子等),那么您的代码和 API 对读者来说应该更有意义。

I would argue that Erlang has no namespaces whatsoever. Modules are global (with the exception of a very unpopular extension to the language), names are global (either to the node or the cluster), pids are global, ports are global, references are global, etc.

Everything is laid flat. The namespacing in Erlang is thus done by convention rather than any other mean. This is why you have <appname>_app, <appname>_sup, etc. as module names. The registered processes also likely follow that pattern, and ETS tables, and so on.

However, you should note that records themselves are not global things: as JUST MY correct OPINION has put it, records are simply a compiler trick over tuples. Because of this, they're local to a module definition. Nobody outside of the module will see a record unless they also include the record definition (either by copying it or with a header file, the later being the best way to do it).

Now I could argue that because you need to include .hrl files and record definitions on a per-module basis, there is no such thing as namespacing records; they're rather scoped in the module, like a variable would be. There is no reason to ever namespace them: just include the right one.

Of course, it could be the case that you include record definitions from two modules, and both records have the same name. If this happens, renaming the records with a prefix might be necessary, but this is a rather rare occurrence in my experience.

Note that it's also generally a bad idea to expose records to other modules. One of the problems of doing so is that all modules depending on yours now get to include its .hrl file. If your module then change the record definition, you will have to recompile every other module that depends on it. A better practice should be to implement functions to interact with the data. Note that get(Key, Struct) isn't always a good idea. If you can pick meaningful names (age, name, children, etc.), your code and API should make more sense to readers.

乱了心跳 2024-10-15 16:33:23

您要么需要以不太可能与其他记录冲突的方式命名所有记录,要么需要不跨模块使用它们。在大多数情况下,我会将记录视为不透明的数据结构,并向定义记录的模块添加功能以访问它。这将避免您遇到的问题。

You'll either need to name all of your records in a way that is unlikely to conflict with other records, or you need to just not use them across modules. In most circumstances I'll treat records as opaque data structures and add functionality to the module that defines the record to access it. This will avoid the issue you've experienced.

世界和平 2024-10-15 16:33:23

我可能会因为他对 Erlang 更深入的了解而在这里给出了糟糕的建议而感到震惊,但我很确定 Erlang 中没有用于记录的命名空间。记录名称只是嫁接到编译器在幕后为您构建的元组前面的原子。 (你看,记录几乎只是对元组的修改。)一旦编译,记录就没有有意义的“命名空间”。

例如,让我们看一下这条记录。

-record(branch, {element, priority, left, right}).

当您在代码中实例化此记录时...

#branch{element = Element, priority = Priority, left = nil, right = nil}.

...另一端出现的是这样的元组:

{branch, Element, Priority, nil, nil}

这就是此时的所有记录。没有实际的“记录”对象,因此命名空间没有任何意义。记录的名称只是一个钉在前面的原子。在 Erlang 中,拥有这个元组和另一个看起来像这样的元组对我来说是完全可以接受的:

{branch, Twig, Flower}

在运行时级别上拥有这两个元组没有问题。

但是......

当然,在代码中将这些作为记录存在一个问题,因为编译器不知道我在实例化时指的是哪个分支。简而言之,如果您希望在 API 中公开记录,则必须执行您所讨论的手动命名空间。

然而,最后一点是关键。为什么要公开 API 中的记录?我从中获取分支记录的代码将该记录用作纯粹不透明的数据类型。我有一个构建分支记录的函数,如果我想公开分支,就是我的 API 中的内容。该函数采用元素优先级等值并返回一条记录(读作:一个元组)。用户无需了解内容。如果我有一个暴露(生物)树结构的模块,它也可以返回一个恰好以原子分支作为其第一个元素的元组,而不会发生任何类型的冲突。

就我个人而言,根据我的口味,在 Erlang API 中公开记录是代码味道。有时可能是必要的,但大多数时候它应该保持隐藏。

I may be slapped down soundly by I GIVE TERRIBLE ADVICE here with his deeper knowledge of Erlang, but I'm pretty sure there is no namespaces for records in Erlang. The record name is just an atom grafted onto the front of the tuple that the compiler builds for you behind the scenes. (Records are pretty much just a hack on tuples, you see.) Once compiled there is no meaningful "namespace" for a record.

For example, let's look at this record.

-record(branch, {element, priority, left, right}).

When you instantiate this record in code...

#branch{element = Element, priority = Priority, left = nil, right = nil}.

...what comes out the other end is a tuple like this:

{branch, Element, Priority, nil, nil}

That's all the record is at this point. There is no actual "record" object and thus namespacing doesn't really make any sense. The name of the record is just an atom tacked onto the front. In Erlang it's perfectly acceptable for me to have that tuple and another that looks like this:

{branch, Twig, Flower}

There's no problem at the run-time level with having both of these.

But...

Of course there is a problem having these in your code as records since the compiler doesn't know which branch I'm referring to when I instantiate. You'd have to, in short, do the manual namespacing you were talking about if you want the records to be exposed in your API.

That last point is the key, however. Why are you exposing records in your API? The code I took my branch record from uses the record as a purely opaque data type. I have a function to build a branch record and that is what will be in my API if I want to expose a branch at all. The function takes the element, priority, etc. values and returns a record (read: a tuple). The user has no need to know about the contents. If I had a module exposing a (biological) tree's structure, it too could return a tuple that happens to have the atom branch as its first element without any kind of conflict.

Personally, to my tastes, exposing records in Erlang APIs is code smell. It may sometimes be necessary, but most of the time it should remain hidden.

楠木可依 2024-10-15 16:33:23

只有一个记录命名空间,与函数和宏不同,只能有一个具有名称的记录。然而,对于记录字段来说,每条记录都有一个命名空间,这意味着不同记录中具有相同名称的字段不会出现问题。这就是为什么记录名称必须始终包含在每个记录访问中的原因之一。

There is only one record namespace and unlike functions and macros there can only be one record with a name. However, for record fields there is one namespace per record, which means that there is no problems in having fields with the same name in different records. This is one reason why the record name must always be included in every record access.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文