Terraform表达式

表达式用来在配置文件中进行一些计算,最简单的表达式就是字面量,比如”hello”,或者5。Terraform也支持一些更加复杂的表达式,比如引用其他resource的输出值、数学计算、布尔条件计算,以及一些内建的函数。

在Terraform配置中很多地方都可以使用表达式,但某些特定的场景下限制了可以使用的表达式的类型,例如只准使用特定数据类型的字面量,或是禁止使用resource的输出值等。

下标和属性

listtuple可以通过下标访问成员,例如local.list[3]、var.tuple[2]。
mapobject可以通过属性访问成员,例如local.object.attrname、local.map.keyname。由于map的key是用户定义的,可能无法成为合法的Terraform标识符,所以访问map成员时推荐使用方括号:local.map[“keyname”]。

引用命名值

Terraform中定义了多种命名值,表达式中的每一个命名值都关联到一个具体的值,可以用单一命名值作为一个表达式,或是组合多个命名值来计算出一个新值。

命名值有如下种类:

  • <RESOURCE TYPE>.<NAME>:表示一个资源对象,如果资源声明了count元参数,那么该表达式表示的是一个对象实例的list;如果资源声明了for_each元参数,那么该表达式表示的是一个对象实例的map
  • var.<NAME>:表示一个输入变量
  • local.<NAME>:表示一个局部值
  • module.<MODULE_NAME>.<OUTPUT_NAME>:表示一个模块的一个输出值
  • data.<DATA_TYPE>.<NAME>:表示一个数据源实例,如果数据源声明了count元参数,那么该表达式表示的是一个数据源实例list;如果数据源声明了for_each元参数,那么该表达式表示的是一个数据源实例map
  • path.module:表示当前模块在文件系统中的路径
  • path.root:表示根模块(调用Terraform命令行执行的代码文件所在的模块)在文件系统中的路径
  • path.cwd:表示当前工作目录的路径,一般来说该路径等同于path.root,但在调用Terraform命令行时如果指定了代码路径,那么二者将会不同
  • terraform.workspace:当前使用的Workspace

虽然这些命名表达式可以使用.<NAME>方式来访问对象的各种属性,但实际上他们实际类型并不是数据类型object。两者的区别在于,object同时支持使用.<NAME>或者["<NAME>"]两种方式访问对象成员属性,而上述命名表达式仅支持.<NAME>

局部命名值

在某些特定表达式或上下文当中,有一些特殊的命名值可以被使用,他们是局部命名值。
几种比较常见的局部命名值有:

  • count.index:表达当前count下标序号
  • each.key:表达当前for_each迭代器实例
  • self:在预置器中指代声明预置器的资源

命名值的依赖关系

构建资源或是模块时经常会使用含有命名值的表达式赋值,Terraform会分析这些表达式并自动计算出对象之间的依赖关系。

引用资源输出属性

最常见的引用类型就是引用一个resourcedata块定义的对象的输出属性,由于这些资源与数据源对象结构可能非常复杂,所以对它们的输出属性的引用表达式也可能非常复杂。
如下示例:

resource "aws_instance" "example" {
  ami           = "ami-abc123"
  instance_type = "t2.micro"

  ebs_block_device {
    device_name = "sda2"
    volume_size = 16
  }
  ebs_block_device {
    device_name = "sda3"
    volume_size = 20
  }
}

aws_instance文档列出了该类型所支持的所有输入参数和内嵌块,以及对外输出的属性列表。所有这些不同的资源类型Schema都可以在引用中使用,如下所示:

  • ami参数可以在可以在其他地方用aws_instance.example.ami表达式来引用

  • id属性可以用aws_instance.example.id的表达式来引用

  • 内嵌的ebs_block_device参数可以通过展开表达式来访问,比如获取所有的ebs_block_devicedevice_name列表:aws_instance.example.ebs_block_device[*].device_name

  • aws_instance类型里的内嵌块并没有任何输出属性,但如果ebs_block_device添加了一个名为”id”的输出属性,那么可以用aws_instance.example.ebs_block_device[*].id表达式来访问含有所有id的列表

  • 有时多个内嵌块会各自包含一个逻辑键来区分彼此,类似用资源名访问资源,也可以用内嵌块的名字来访问特定内嵌块。假如aws_instance类型有一个假想的内嵌块类型device并规定device可以赋予这样的一个逻辑键,那么代码看起来就会是这样的:

    device "foo" {
      size = 2
    }
    device "bar" {
      size = 4
    }

    可以使用键来访问特定块的数据,例如:aws_instance.example.device["foo"].size。要获取一个device名称到device大小的映射,可以使用for表达式:

    {for k, device in aws_instance.example.device : k => device.size}
  • 当一个资源声明了count参数,那么资源本身就成了一个资源对象列表而非单个资源。这种情况下要访问资源输出属性,要么使用展开表达式,要么使用下标索引:

    • aws_instance.example[*].id:返回所有instance的id列表
    • aws_instance.example[0].id:返回第一个instance的id
  • 当一个资源声明了for_each参数,那么资源本身就成了一个资源对象字典而非单个资源。这种情况下要访问资源的输出属性,要么使用特定键,要么使用for表达式:

    • aws_instance.example["a"].id:返回”a”对应的实例的id
    • [for value in aws_instance.example: value.id]:返回所有instance的id
      注意:
      (1)使用for_each的资源集合不能直接使用展开表达式,展开表达式只能适用于列表
      (2)可以把字典转换成列表后再使用展开表达式:values(aws_instance.example)[*].id

尚不知晓的值

当Terraform在计算变更计划时,有些资源输出属性无法立即求值,因为它们的值取决于远程API的返回值。例如,有一个远程对象可以在创建时返回一个生成的唯一id,Terraform无法在创建它之前就预知这个值。

为了允许在计算变更阶段就能计算含有这种值的表达式,Terraform使用了一个特殊的”尚不知晓(unknown value)”占位符来代替这些结果。大部分时候不需要特意理会它们,因为Terraform语言会自动处理这些尚不知晓的值,比如说使两个尚不知晓的值相加得到的会是一个尚不知晓的值。

然而,有些情况下表达式中含有尚不知晓的值会有明显的影响:

  • count元参数不可以为尚不知晓,因为变更计划必须明确地知晓到底要维护多少个目标实例
  • 如果尚不知晓的值被用于数据源,那么数据源在计算变更计划阶段就无法读取,它会被推迟到执行阶段读取,这种情况下在计划阶段该数据源的一切输出均为尚不知晓
  • 如果声明module块时传递给模块输入变量的表达式使用了尚不知晓值,那么在模块代码中任何使用了该输入变量值的表达式的值都将是尚不知晓
  • 如果模块输出值表达式中含有尚不知晓值,任何使用该模块输出值的表达式都将是尚不知晓
  • Terraform会尝试验证尚不知晓值的数据类型是否合法,但仍然有可能无法正确检查数据类型,导致执行阶段发生错误

尚不知晓值在执行terraform plan时会被输出为”(not yet known)”。

算数和逻辑操作符

Terraform语言支持一组算数和逻辑操作符,它们的功能类似于JavaScript或Ruby里的操作符功能。
当一个表达式中含有多个操作符时,它们的优先级顺序时:

  • !- (负号)
  • */%
  • +- (减号)
  • >>=<<=
  • ==!=
  • &&
  • ||

可以使用小括号覆盖默认优先级。
不同的操作符可以按它们之间相似的行为被归纳为几组,每一组操作符都期待被给予特定类型的值。
Terraform会在类型不符时尝试进行隐式类型转换,如果失败则会抛错。

算数操作符

  • a + b:返回a与b的和
  • a - b:返回a与b的差
  • a * b:返回a与b的积
  • a / b:返回a与b的商
  • a % b:返回a与b的模(该操作符一般仅在a与b是整数时有效)
  • -a:返回a与-1的商

相等性操作符

  • a == b:如果a与b类型与值都相等返回true,否则返回false
  • a != b:与==相反

比较操作符

  • a < b:如果a比b小则为true,否则为false
  • a > b:如果a比b大则为true,否则为false
  • a <= b:如果a比b小或者相等则为true,否则为false
  • a >= b:如果a比b大或者相等则为true,否则为false

逻辑操作符

  • a || b:a或b中有至少一个为true则为true,否则为false
  • a && b:a与比都为true则为true,否则为false
  • !a:如果a为true则为false,如果a为false则为true

条件表达式

条件表达式是判断一个布尔表达式的结果以便于在后续两个值当中选择一个:

condition ? true_val : false_val

如果condition表达式为true,那么结果是true_value,反之则为false_value。

一个常见的条件表达式用法是使用默认值替代非法值:

var.a != "" ? var.a : "default-a"

如果输入变量a的值是空字符串,那么结果会是default-a,否则返回输入变量a的值。

条件表达式的判断条件可以使用上述的任意操作符,供选择的两个值也可以是任意类型,但它们的类型必须相同,这样Terraform才能判断条件表达式的输出类型。

函数调用

Terraform支持在计算表达式时使用一些内建函数,函数调用表达式类似操作符,通用语法是:

<FUNCTION NAME>(<ARGUMENT 1>, <ARGUMENT 2>)

函数名标明了要调用的函数,每一个函数都定义了数量不等、类型不一的入参以及不同类型的返回值。

有些函数定义了不定长的入参表,例如,min函数可以接收任意多个数值类型入参,返回其中最小的数值:

min(55, 3453, 2)

展开函数入参

如果想要把列表或元组的元素作为参数传递给函数,可以使用展开符:

min([55, 2453, 2]...)

展开符使用的是三个独立的.号组成的...,展开符是一种只能用在函数调用场景下的特殊语法。

for表达式

for表达式是将一种复杂类型映射成另一种复杂类型的表达式,输入类型值中的每一个元素都会被映射为一个或零个结果。
举例来说,如果var.list是一个字符串列表,那么下面的表达式将会把列表元素全部转为大写:

[for s in var.list : upper(s)]

在这里for表达式迭代了var.list中每一个元素(就是s),然后计算了upper(s),最后构建了一个包含了所有upper(s)结果的新元组,元组内元素顺序与源列表相同。

for表达式周围的括号类型决定了输出值的类型。
上面的例子里使用了方括号,所以输出类型是元组;如果使用的是花括号,那么输出类型是对象,for表达式内部冒号后面应该使用以=>符号分隔的表达式:

{for s in var.list : s => upper(s)}

该表达式返回一个对象,对象的成员属性名称就是源列表中的元素,值就是对应的大写值。

一个for表达式还可以包含一个可选的if子句用以过滤结果,这可能会减少返回的元素数量:

[for s in var.list : upper(s) if s != ""]

被for迭代的也可以是对象或者字典,这样的话迭代器就会被表示为两个临时变量:

[for k, v in var.map : length(k) + length(v)]

最后,如果返回类型是对象(使用花括号)那么表达式中可以使用...符号实现group by:

{for s in var.list : substr(s, 0, 1) => s... if s != ""}

展开表达式

展开表达式提供了一种类似for表达式的简洁表达方式。
例如var.list包含一组对象,每个对象有一个属性id,那么读取所有id的for表达式会是这样:

[for o in var.list : o.id]

与之等价的展开表达式是这样的:

var.list[*].id

这个特殊的[*]符号迭代了列表中每一个元素,然后返回了它们在.号右边的属性值。

展开表达式只能被用于列表(所以使用for_each参数的资源不能使用展开表达式,因为它的类型是字典)。然而,如果一个展开表达式被用于一个既不是列表又不是元组的值,那么这个值会被自动包装成一个单元素的列表然后被处理。

即:var.single_object[*].id等价于[var.single_object][*].id,大部分场景下这种行为没有什么意义,但在访问一个不确定是否会定义count参数的资源时,这种行为很有帮助,例如:

aws_instance.example[*].id

上面的表达式不论aws_instance.example定义了count与否都会返回实例的id列表,这样如果以后为aws_instance.example添加了count参数我们也不需要修改这个表达式。

dynamic块

在顶级块(例如resource)当中,一般只能以类似name = expression的形式进行一对一的赋值。大部分情况下这已经够用了,但某些资源类型包含了可重复的内嵌块,无法使用表达式循环赋值:

resource "aws_elastic_beanstalk_environment" "tfenvtest" {
  name = "tf-test-name"

  # 在aws_elastic_beanstalk_environment中通常会包含多个setting块
  setting {
    namespace = "aws:ec2:vpc"
    name      = "VPCId"
    value     = "vpc-xxxxxxxx"
  }

  setting {
    namespace = "aws:ec2:vpc"
    name      = "Subnets"
    value     = "subnet-xxxxxxxx"
  }
}

可以用dynamic块来动态构建重复的setting这样的内嵌块:

resource "aws_elastic_beanstalk_environment" "tfenvtest" {
  name                = "tf-test-name"
  application         = "${aws_elastic_beanstalk_application.tftest.name}"
  solution_stack_name = "64bit Amazon Linux 2018.03 v2.11.4 running Go 1.12.6"

  dynamic "setting" {
    for_each = var.settings
    content {
      namespace = setting.value["namespace"]
      name = setting.value["name"]
      value = setting.value["value"]
    }
  }
}

dynamic可以在resourcedataproviderprovisioner块内使用。
一个dynamic块类似于for表达式,只不过它产生的是内嵌块,它可以迭代一个复杂类型数据然后为每一个元素生成相应的内嵌块。
在上面的例子里:

  • dynamic的标签(也就是”setting”)确定了要生成的内嵌块种类
  • for_each参数提供了需要迭代的复杂类型值
  • iterator参数(可选)设置了用以表示当前迭代元素的临时变量名,如果没有设置iterator,那么临时变量名默认就是dynamic块的标签(也就是setting)
  • labels参数(可选)是一个表示块标签的有序列表,用以按次序生成一组内嵌块,有labels参数的表达式里可以使用临时的iterator变量
  • 内嵌的content块定义了要生成的内嵌块的块体,可以在content块内部使用临时的iterator变量

由于for_each参数可以是集合或者结构化类型,所以可以使用for表达式或是展开表达式来转换一个现有集合的类型。

iterator变量(上面的例子里就是setting)有两个属性:

  • key:迭代容器如果是map,那么就是当前元素的键;迭代容器如果是list,那么就是当前元素在list中的下标序号;如果是由for_each表达式产出的set,那么key和value是一样的,这时不应该使用key
  • value:当前元素的值

一个dynamic块只能生成属于当前块定义过的内嵌块参数,无法生成诸如lifecycleprovisioner这样的元参数,因为Terraform必须在确保对这些元参数求值的计算是成功的。

for_each的值必须是不为空的map或者set,如果你需要根据内嵌数据结构或者多个数据结构的元素组合来声明资源实例集合,可以使用Terraform表达式和函数来生成合适的值。

注意: 过度使用dynamic块会导致代码难以阅读以及维护,建议只在需要构造可重用的模块代码时使用dynamic块,尽可能手写内嵌块。

字符串字面量

Terraform有两种不同的字符串字面量,最通用的就是用一对双引号包裹的字符,比如”hello”。在双引号之间,反斜杠\被用来进行转义。
Terraform支持的转义符有:

符号说明
\n换行
\r回车
\t制表符
\"双引号 (不会截断字符串)
\\反斜杠
\uNNNN普通字符映射平面的Unicode字符(NNNN代表四位16进制数)
\UNNNNNNNN补充字符映射平面的Unicode字符(NNNNNNNN代表八位16进制数)

另一种字符串表达式被称为”heredoc”风格,是受Unix Shell语言启发。它可以使用自定义的分隔符更加清晰地表达多行字符串:

<<EOT
hello
world
EOT

<<标记后面直到行尾组成的标识符(上述例子为EOT)开启了字符串,然后Terraform会把剩下的行都添加进字符串,直到遇到与标识符完全相等的字符串为止。
在上面的例子里,EOT就是标识符。任何字符都可以用作标识符,但传统上标识符一般以EO起头。上面例子里的EOT代表”文本的结束(end of text)”。

上面例子里的heredoc风格字符串要求内容必须对齐行头,这在块内声明时看起来会比较奇怪:

block {
  value = <<EOT
hello
world
EOT
}

为了改进可读性,Terraform也支持缩进的heredoc,只要把<<改成<<-

block {
  value = <<-EOT
  hello
    world
  EOT
}

上面的例子里,Terraform会以最靠近行头的行作为基准来调整行头缩进,得到的字符串是这样的:

hello
  world

heredoc中的反斜杠不会被解释成转义,而只会是简单的反斜杠。

双引号和heredoc风格两种字符串都支持字符串模版,模版的形式是${...}以及%{...}。如果想要表达${或者%{的字面量,那么可以重复第一个字符:$${%%{

字符串模版

字符串模版允许在字符串中嵌入表达式,或是通过其他值动态构造字符串。

插值

一个${...}序列被称为插值,插值计算花括号之间的表达式的值,有必要的话将之转换为字符串,然后插入字符串模版,形成最终的字符串:

"Hello, ${var.name}!"

输入变量var.name的值被访问后插入了字符串模版,产生了最终的结果,比如:”Hello, Juan!” 。

命令

一个%{...}序列被称为命令,命令可以是一个布尔表达式或者是对集合的迭代,类似条件表达式以及for表达式。

有两种命令:

  • if <BOOL> / else / endif命令根据布尔表达式的结果在两个模版中选择一个:

    "Hello, %{ if var.name != "" }${var.name}%{ else }unnamed%{ endif }!"

    else部分可以省略,这样如果布尔表达结果为false那么就会插入空字符串。

  • for <NAME> in <COLLECTION> / endfor命令迭代一个结构化对象或者集合,用每一个元素渲染模版,然后把它们拼接起来:

    <<EOT
    %{ for ip in aws_instance.example.*.private_ip }
    server ${ip}
    %{ endfor }
    EOT

    for关键字后紧跟的名字被用作代表迭代器元素的临时变量,可以用来在内嵌模版中使用。

为了在不添加额外空格和换行的前提下提升可读性,所有的模版序列都可以在首尾添加~符号。如果有~符号,那么模版序列会去除字符串左右的空白(空格以及换行)。如果~出现在头部,那么会去除字符串左侧的空白;如果出现在尾部,那么会去除字符串右边的空白:

<<EOT
%{ for ip in aws_instance.example.*.private_ip ~}
server ${ip}
%{ endfor ~}
EOT

如上示例,命令符后面的换行符被忽略了,但是server ${ip}后面的换行符被保留了,这确保了每一个元素生成一行输出:

server 10.1.16.154
server 10.1.16.1
server 10.1.16.34

当使用模版命令时,推荐使用heredoc风格字符串,用多行模版提升可读性;双引号字符串内最好只使用插值。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/598492.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

效率跨越式提升的工农业对机器人专业的需求

需求 需要用人的地方一定会逐步收缩。 原来需要人的地方也会逐步被机器人取代。 机器人这个专业最强的悖论就是可以部分取代人。 此处&#xff1a;用人的地方是指“工农业”&#xff0c;包括工业和农业。 机器人工程行业算制造业吗 机器人工程终身学习和工作计划 趋势 工匠…

1077 互评成绩计算

solution 总成绩 &#xff08;老师成绩 同学去掉最高分去掉最低分的平均分&#xff09;/2&#xff0c;其中总成绩四舍五入取整 #include<iostream> #include<algorithm> using namespace std; int main(){int n, m, worst, better, sum, g, x, cnt;scanf("…

【数学建模】天然肠衣搭配问题

2011高教社杯全国大学生数学建模竞赛D题 天然肠衣&#xff08;以下简称肠衣&#xff09;制作加工是我国的一个传统产业&#xff0c;出口量占世界首位。肠衣经过清洗整理后被分割成长度不等的小段&#xff08;原料&#xff09;&#xff0c;进入组装工序。传统的生产方式依靠人工…

每日OJ题_DFS解决FloodFill⑤_力扣417. 太平洋大西洋水流问题

目录 力扣417. 太平洋大西洋水流问题 解析代码 力扣417. 太平洋大西洋水流问题 417. 太平洋大西洋水流问题 难度 中等 有一个 m n 的矩形岛屿&#xff0c;与 太平洋 和 大西洋 相邻。 “太平洋” 处于大陆的左边界和上边界&#xff0c;而 “大西洋” 处于大陆的右边界和下…

自动控制原理MATLAB:控制系统模型构建

在MATLAB中&#xff0c;常用的系统建模方法有传递函数模型、零极点模型以及状态空间模型等。 1系统传递函数模型描述&#xff1a; 命令格式&#xff1a; systf(num,den,Ts); 其中&#xff0c;num、den为分子多项式降幂排列的系数向量,Ts表示采样时间&#xff0c;缺省时描述…

AI 数据观 | TapData Cloud + MongoDB Atlas:大模型与 RAG 技术有机结合,落地实时工单处理智能化解决方案

本篇为「AI 数据观」系列文章第二弹&#xff0c;在这里&#xff0c;我们将进一步探讨 AI 行业的数据价值。以 RAG 的智能工单应用场景为例&#xff0c;共同探索如何使用 Tapdata Cloud MongoDB Atlas 实现具备实时更新能力的向量数据库&#xff0c;为企业工单处理的智能化和自…

在小黑框如何用Python写出多行代码

平时使用python自带的小黑框编译器只能一行代码一行代码的写&#xff0c; 方法一 可以新建一个文本txt格式&#xff0c;然后打开在里面输入你想要的Python代码&#xff0c;然后把名字改成xxx.py&#xff0c;然后点击小黑框&#xff0c;输入 python 把Py文件拖过来回车就行 方…

Hive内部表、外部表

Hive内部表、外部表 1. 内部表&#xff08;Managed Table&#xff09;&#xff1a; 内部表是由Hive完全管理的表&#xff0c;包括数据和元数据。当你删除内部表时&#xff0c;Hive会同时删除表的数据和元数据。内部表的数据存储在Hive指定的默认位置&#xff08;通常是HDFS上…

VBA 创建透视表,录制宏,自动化报表

目录 一. 数据准备二. 需求三. 准备好报表模板四. 执行统计操作&#xff0c;录制宏4.1 根据数据源创建透视表4.2 填充数据到报表4.3 结束宏录制 五. 执行录制好的宏&#xff0c;自动化报表 一. 数据准备 ⏹数据源1 姓名学科成绩丁志敏语文91李平平语文81王刚语文64张伊语文50…

【前端】HTML基础(1)

文章目录 前言一、什么是前端二、HTML基础1、 HTML结构1.1 什么是HTML页面1.2 认识HTML标签1.3 HTML文件基本结构1.3 标签层次结构1.4 创建html文件1.5 快速生成代码框架 三、Emmet快捷键 前言 这篇博客仅仅是对HTML的基本结构进行了一些说明&#xff0c;关于HTML的更多讲解以及…

新能源电燃灶:为人类社会贡献高品质的健康生活

华火新能源电燃灶&#xff0c;作为一种创新的厨房设备&#xff0c;近年来逐渐走进了千家万户&#xff0c;成为了现代家庭厨房的新宠。它不仅改变了传统的烹饪方式&#xff0c;更在环保、节能、安全等方面为人类带来了诸多贡献。本文将从多个方面探讨华火新能源电燃灶对人类的贡…

知行之桥EDI系统跨平台版本安装报错及解决方案

本文将为大家介绍如何在Windows系统中安装知行之桥EDI系统跨平台版本的常见报错以及解决方案。如下图所示&#xff1a; 在知行软件官网的导航栏中点击 下载 按钮&#xff0c;即可看到知行之桥EDI系统不同版本的下载选项&#xff0c;点击右侧跨平台版本&#xff0c;选择 Windows…

移动硬盘无法被识别怎么办?恢复移动硬盘3个正确做法

移动硬盘已成为我们日常生活和工作中不可或缺的数据存储设备。然而当移动硬盘突然无法被电脑识别时&#xff0c;往往会让人倍感焦虑。面对这种情况我们不必过于慌张&#xff0c;下面一起来看看指南解决。 解决方法一&#xff1a;检查硬件连接与供电 检查接口连接&#xff1a…

uniapp离线在Xcode上打包后提交审核时提示NSUserTrackingUsageDescription的解决方法

uniapp离线在Xcode上打包后提交审核时提示NSUserTrackingUsageDescription的解决方法 问题截图&#xff1a; 亲测有效的方法 方法一&#xff1a; 选择通过uniapp的开发工具Hbuilder来进行在线打包&#xff0c;取消默认勾选的以下选项。 然后进行在线打包就不会存在提交审…

山东省文史书画研究会成立20周年系列活动徽标征集胜选名单公布

2024年5月1日&#xff0c;山东省文史书画研究会成立20周年系列活动徽标征集落下帷幕。征稿启事下发后&#xff0c;得到社会各界人士的广泛关注与参与&#xff0c;共收到设计方案608件。经过初评&#xff0c;选出5幅作品进入复评&#xff0c;并经过网络投票和专家投票相结合的方…

linux——主从同步

1. 保证主节点开始二进制日志&#xff0c;从节点配置中继日志 2. 从节点的开启一个 I/O 线程读取主节点二进制日志的内容 3. 从节点读取主节点的二进制日志之后&#xff0c;会将去读的内容写入从节点的中继日志 4. 从节点开启 SQL 线程&#xff0c;读取中继日志的内容&a…

《软件方法(下)》8.3 建模步骤C-2 识别类的关系(202405更新)

DDD领域驱动设计批评文集 做强化自测题获得“软件方法建模师”称号 《软件方法》各章合集 8.3 建模步骤C-2 识别类的关系 首先重复本章开头所提到的&#xff1a; 虽然本书先讲解“识别类和属性”&#xff0c;再讲解“识别类的关系”&#xff0c;但在实际工作中&#xff0c;…

数据库管理-第184期 23ai:干掉MongoDB的不一定是另一个JSON数据库(20240507)

数据库管理184期 2024-05-07 数据库管理-第184期 23ai:干掉MongoDB的不一定是另一个JSON数据库&#xff08;20240507&#xff09;1 JSON需求2 关系型表设计3 JSON关系型二元性视图3 查询视图总结 数据库管理-第184期 23ai:干掉MongoDB的不一定是另一个JSON数据库&#xff08;20…

9.4k Star!MemGPT:伯克利大学最新开源、将LLM作为操作系统、无限上下文记忆、服务化部署自定义Agent

9.4k Star&#xff01;MemGPT&#xff1a;伯克利大学最新开源、将LLM作为操作系统、无限上下文记忆、服务化部署自定义Agent 原创 Aitrainee | 公众号&#xff1a;AI进修生&#xff1a;AI算法工程师 / Prompt工程师 / ROS机器人开发者 | 分享AI动态与算法应用资讯&#xff0c;提…

人脸采集训练识别

项目概述&#xff1a; 本地摄像头采集人脸数据集&#xff0c;通过训练得到trainingData.yml模型&#xff0c;加载haarcascade_frontalface_default.xml实现人脸识别。haarcascade_frontalface_default.xml 文件并不是一个完整的人脸识别模型&#xff0c;而是一个用于检测正脸&a…
最新文章