如何在配置中仅覆盖明确指定的键作为映射的一部分?

How to overwrite only explicitly specified keys, as a part of a map, in a config?

在 config/config.exs 中我有这个:

config :my_app, :settings,
  my_key: %{
    key1: "default-key1",
    key2: "default-key2",
    key3: "default-key3"
  }

并在 config/dev.exs 中:

config :my_app, :settings,
  my_key: %{
    key1: "key1-dev-value",
  }

并且在 config/prod.exs 中:

config :my_app, :settings,
  my_key: %{
    key1: "key1-prod-value",
  }

我希望所有键都保留其所有初始值,但我明确覆盖的键除外。

但是,dev.exsprod.exs 中的这段代码 将完全覆盖 my_key,因此只剩下 key1,其他 2 - key2key3 将消失。

如何解决?

我不考虑使用第三方库,也不考虑env。变量,我也不想将键及其值从一个配置复制粘贴到其他配置。

如果您使用关键字列表而不是地图,它会起作用:

# config/config.exs

config :my_app, :settings,
  my_key: [
    key1: "default-key1",
    key2: "default-key2",
    key3: "default-key3"
  ]

# config/dev.exs

config :my_app, :settings,
  my_key: [
    key1: "key1-dev-value",
  ]

获取配置(在开发模式下):

> Application.fetch_env(:my_app, :settings)
{:ok,
 [my_key: [key2: "default-key2", key3: "default-key3", key1: "key1-dev-value"]]}

更新地图可以在 a few ways 中完成,但我认为这适用于 config/prod.exs:

config :my_app, :settings,
  my_key: %{my_key | key1: "key1-prod-value"}

或者,也许有一个更具可读性的选项:

config :my_app, :settings,
  my_key: Map.put(my_key, :key1, "key1-prod-value")

它将采用已经定义的 my_key 并更新其中预先存在的 key1,返回完整更新的 my_key 映射。

如果您的应用拥有您正在设置的配置并且您能够更改结构,我认为@zwippie 的回答是最好的。如果没有,另一种选择是 config/config.exs 内的 case

key1 =
  case config_env() do
    :prod ->
      "key1-prod-value"

    :dev ->
      "key1-dev-value"

    :test -> # or _env
      "default-key1"
  end

config :my_app, :settings,
  my_key: %{
    key1: key1,
    key2: "default-key2",
    key3: "default-key3"
  }