Inheritance YAML中更复杂的继承?

Inheritance YAML中更复杂的继承?,inheritance,yaml,Inheritance,Yaml,亚马尔有继承权。我见过的最明显的例子是: 我需要更复杂的东西:我需要覆盖对象的对象属性。以下是一个例子: database: &default server: ip: 192.168.1.5 port: 2000 db_name: test user: name: root password: root # database foo differs from default by only its port and user passwor

亚马尔有继承权。我见过的最明显的例子是:

我需要更复杂的东西:我需要覆盖对象的对象属性。以下是一个例子:

database: &default
  server:
    ip: 192.168.1.5
    port: 2000
  db_name: test
  user: 
    name: root
    password: root

# database foo differs from default by only its port and user password
foo_database:
  <<: *default
  server:
    port: 2001
  db_name: foo
  user:
    password: foo_root
但是如果您这样声明,您将得到不正确的属性(根据预期值):

因为新的“服务器”对象只有“端口”属性,它覆盖了整个旧的“服务器”对象

我怎样才能得到我想要的遗产

编辑 我对以下工作代码的确切意图:


不幸的是,您无法获得想要实现的“继承”,因为YAML的“继承”更像是一种“合并散列”

在使用
*默认
别名时展开配置,您有:

foo_database:
  server:
    ip: 192.168.1.5
    port: 2000
  db_name: test
  user: 
    name: root
    password: root
如果以后使用具有相同键的散列,它们将完全覆盖前面声明的散列,留下(请原谅格式):

因此,在您的情况下,似乎由于配置不完全相同,使用锚和别名来干燥配置可能不是正确的方法

有关此问题的更多参考资料如下:

编辑 如果您真的愿意,我认为您可以按如下方式重新配置YAML,以获得您想要的内容,但在您的情况下,我认为额外的混淆不值得:

server_defaults: &server_defaults
  ip: 192.168.1.5
  port: 2000

user_defaults: &user_defaults
  name: root
  password: root

database: &default
  server:
    <<: *server_defaults
  db_name: test
  user: 
    <<: *user_defaults

foo_database:
  <<: *default
  server:
    <<: *server_defaults
    port: 2001
  db_name: foo
  user:
    <<: *user_defaults
    password: foo_root
server\u默认值:&server\u默认值
ip:192.168.1.5
港口:2000
用户默认值:&用户默认值
姓名:root
密码:root
数据库:&默认值
服务器:

这个怎么样?使用多个锚

database: &default
  server: &server
    ip: 192.168.1.5
    port: 2000
  db_name: test
  user: &user
    name: root
    password: root

foo_database:
  <<: *default
  server:
    << : *server
    port: 2001
  db_name: foo
  user:
    << : *user
    password: foo_root
数据库:&默认值
服务器:&服务器
ip:192.168.1.5
港口:2000
db_名称:test
用户:&用户
姓名:root
密码:root
foo_数据库:

对于这类问题,我创建了一个工具:。 通过使用+jqfront,您可以通过稍微修改输入来实现它

in.yaml:

$local: 
  database_default:
    server:
      ip: 192.168.1.5
      port: 2000
    db_name: test
    user: 
      name: root
      password: root

# database foo differs from default by only its port and user password
foo_database:
  $extends: [ database_default ]
  server:
    port: 2001
  db_name: foo
  user:
    password: foo_root
您可以通过以下命令行处理此文件

$ yq . -j in.yaml | jq-front  | yq . -y
您将得到您想要的以下输出

foo_database:
  server:
    ip: 192.168.1.5
    port: 2001
  db_name: foo
  user:
    name: root
    password: foo_root
注意:jq前端非常慢。在我的机器上,这个命令花了2.5秒,这对我来说并不重要,因为系统配置可以读取一次,并且我的程序的其余部分只能使用转换后的文件

注意:如果您使用docker+bash,docker安装JQFront会容易得多。您只需将以下函数添加到
.bashrc
或其来源的文件中

function jq-front() {
  docker run --rm -i \
    -v /:/var/lib/jf \
    -e JF_PATH_BASE="/var/lib/jf" \
    -e JF_PATH="${JF_PATH}" \
    -e JF_DEBUG=${JF_DEBUG:-disabled} \
    -e JF_CWD="$(pwd)" \
    dakusui/jq-front:"${JF_DOCKER_TAG:-latest}" "${@}"
}

我们说的或多或少是同一件事。“变通方法”在技术上是可行的,但“实际上”是行不通的,因为YAML的目标是让人可读。我举了一个微不足道的例子。假设我们有一个对象,它有大约100条线和1到6个子对象。如果我们只需要在其中一个位于最深节点的位置更改1-2个对象,则所有位置都将被锚填满。锚定命名问题更大。这是一种需要。我问这个问题是因为我需要知道我的方法是否错了。如果没有,我将尝试实现这种继承。我同意YAML应该是人类可读的,因此我不建议在我的编辑中使用该解决方案(我只是在您非常坚持希望以问题中指定的方式获得结果的情况下才写下它)。就我个人而言,我只在YAML中使用过锚和别名来重构任何重复的代码。我从未对重复的代码使用别名,然后覆盖其中一些代码(如上面的编辑),因为我认为这会使代码更难阅读。如果你想让事情让人读得懂,在你的情况下,这可能意味着要保留一些重复。谢谢你认真的回答。是的,您是对的,在这些条件下,重复代码会更清晰。但是现在我要介绍一个新的继承操作符(不,不,不要阻止我!:P)作为“不客气,祝你好运。如果你最终配置了一些有趣的东西,请通过编辑你的问题来分享它:-)@ceremcem你曾经(部分地)做过吗?”完成
我没有想到的是你怎么说你有6个级别的深度。这有点烦人。我觉得比没有继承的好处更好。这个链接实际上不再加载文章,这有点恼火。我更新了链接,指向archive.org版本。我的编辑仍在编辑中查看。在此之前:该链接感谢更新。我认为StackOverflow中的通知有点问题;如果我收到关于第一条消息的通知,我会很乐意处理这个问题。无论如何,谢谢。
server_defaults: &server_defaults
  ip: 192.168.1.5
  port: 2000

user_defaults: &user_defaults
  name: root
  password: root

database: &default
  server:
    <<: *server_defaults
  db_name: test
  user: 
    <<: *user_defaults

foo_database:
  <<: *default
  server:
    <<: *server_defaults
    port: 2001
  db_name: foo
  user:
    <<: *user_defaults
    password: foo_root
database: &default
  server: &server
    ip: 192.168.1.5
    port: 2000
  db_name: test
  user: &user
    name: root
    password: root

foo_database:
  <<: *default
  server:
    << : *server
    port: 2001
  db_name: foo
  user:
    << : *user
    password: foo_root
$local: 
  database_default:
    server:
      ip: 192.168.1.5
      port: 2000
    db_name: test
    user: 
      name: root
      password: root

# database foo differs from default by only its port and user password
foo_database:
  $extends: [ database_default ]
  server:
    port: 2001
  db_name: foo
  user:
    password: foo_root
$ yq . -j in.yaml | jq-front  | yq . -y
foo_database:
  server:
    ip: 192.168.1.5
    port: 2001
  db_name: foo
  user:
    name: root
    password: foo_root
function jq-front() {
  docker run --rm -i \
    -v /:/var/lib/jf \
    -e JF_PATH_BASE="/var/lib/jf" \
    -e JF_PATH="${JF_PATH}" \
    -e JF_DEBUG=${JF_DEBUG:-disabled} \
    -e JF_CWD="$(pwd)" \
    dakusui/jq-front:"${JF_DOCKER_TAG:-latest}" "${@}"
}