Elixir中模块的结构重用

Cri*_*cia 5 elixir

有什么机制可以实现结构重用:定义一个结构,其中包含另一个结构的所有字段以及它自己的一些结构.

我有这些看起来像这样的结构

defmodule VideoView do
  defstruct name: nil, description: nil, video_link: nil, ...
end

defmodule ImagesView do
  defstruct name: nil, description: nil, images: [], ...
end

defmodule Model3DView do
  defstruct name: nil, description: nil, model: nil, ...
end
Run Code Online (Sandbox Code Playgroud)

其中有7个.在我的UML它们都继承了View它有namedescription.我希望他们所有人分享这些共同的领域,特别是如果我决定添加或删除一个公共领域,这可能是当前方法的真正痛苦.

Pat*_*ity 10

正如其他人所建议的那样,你应该再考虑一下你是否真的从重新使用结构中获得了那么多.

如果仍然需要它来减少大量复制,可以使用模块属性来初始存储struct选项.然后你可以重复使用它们defstruct并通过一个函数将它们暴露给其他模块:

defmodule View do
  @common_fields [name: nil, description: nil]
  def common_fields, do: @common_fields
  defstruct @common_fields
end
Run Code Online (Sandbox Code Playgroud)

如果您不打算单独使用View,可以直接将公共字段放在函数中:

defmodule View do
  def common_fields do
    [name: nil, description: nil]
  end
end
Run Code Online (Sandbox Code Playgroud)

然后,您可以使用其他结构中的公共字段,如下所示:

defmodule VideoView do
  defstruct View.common_fields ++ [video_link: nil, ...]
end

defmodule ImagesView do
  defstruct View.common_fields ++ [images: [], ...]
end

defmodule Model3DView do
  defstruct View.common_fields ++ [model: nil, ...]
end
Run Code Online (Sandbox Code Playgroud)


Fre*_*Dog 2

据我所知,没有直接的方法可以做到 1。如果你对宏的了解足够多,你可能可以找到一个。Elixir 中的结构体实际上是一个零参数的函数__struct__/0,它返回一个带有默认值的映射。

您可以将另一个模块的函数导入到您的模块中,并且如果其他模块中的函数定义为可重写,则可以使用您自己的定义来重写其他模块中定义的函数。

use OtherModule
Run Code Online (Sandbox Code Playgroud)

但你不能导出这些函数,只能导出模块中定义的函数。

如果你想要继承 Elixir 不是你想要使用的语言。Elixir 不关注继承,而是关注函数的组合和数据的转换。从面向对象的世界带来大量包袱只会减慢你的速度。

在这种情况下,如果您需要来自另一个模块的数据结构,您应该考虑组合而不是继承。一种方法是

defstruct other_module: struct(Other_Module), foo: nil , bar: 1 
Run Code Online (Sandbox Code Playgroud)

在大多数情况下,Elixir 是一种基于表达式的语言,您几乎总是可以为运行时函数调用交换数据值,反之亦然。