Rust循环和函数

下面聊聊以下主题:

  • 基于条件的分支
  • 循环
  • 函数
  • 属性
  • 测试

基于条件的分支

基于条件的分支,可以通过常见的 if、if else 或 if else if else 构造来完成,例如下面的示例:

fn main() { let dead = false; let health = 48; if dead { println!("游戏结束!"); return; } if dead { println!("游戏结束!"); return; } else { println!("你还有机会赢!"); } if health >= 50 { println!("继续战斗!"); } else if health >= 20  { println!("停止战斗并恢复力量!"); } else { println!("躲起来尝试恢复!"); } 
}  

这将产生以下输出:

你还有机会赢!
停止战斗并恢复力量!

if 语句后的条件必须是布尔值。然而,与 C 语言不同的是,这个条件不需要用括号括起来。在 if、else 或 else if 语句后需要使用 { }(大括号)括起来的代码块。第一个示例还展示了我们可以通过返回值来退出函数。

另外,if else 条件是一个返回值的表达式。这个值可以作为函数调用参数在 print! 语句中使用,或者可以在 let 绑定中赋值,像这样:

let active = if health >= 50 { true } else { false }; 
println!("我活跃吗? {}", active);  

这将打印以下输出:

我活跃吗? false

代码块可以包含多行,但要注意:当返回一个值时,你必须在 if 或 else 块的最后一个表达式后省略分号(参见 第2章 使用变量和类型 中的表达式部分)。此外,所有分支必须始终返回相同类型的值。

这也减少了对三元运算符(?:)的需求,就像在 C++ 中一样;简单地使用 if,如下所示:

let adult = true; 
let age = if adult { "+18" } else { "-18" }; 
println!("年龄是 {}", age);  //  

这将产生以下输出:

年龄是 +18

循环

对于重复的代码片段,Rust 提供了常见的 while 循环,同样不需要在条件周围加上括号:

fn main() { let max_power = 10; let mut power = 1; while power < max_power { print!("{} ", power); // 打印不换行 power += 1;           // 计数器增加 } 
}  

这将打印以下输出:

    1 2 3 4 5 6 7 8 9

要开始一个无限循环,请使用 loop 语句,如下所示:

loop { power += 1; if power == 42 { // 跳过此次迭代的剩余部分continue; } print!("{}  ", power); if power == 50 { print!("好了,今天就到这里"); break;  // 退出循环 } 
}  

打印包括 50 但不包括 42 的所有 power 值;然后循环通过 break 语句停止。由于 continue 语句,42 不被打印。因此,loop 相当于 while true,带有条件的 break 的 loop 模拟其他语言中的 do while。

当循环嵌套在彼此内部时,break 和 continue 语句适用于直接包围的循环。任何循环语句(包括我们接下来将看到的 while 和 for 循环)都可以在前面带有标签(表示为 labelname:),以便我们跳转到下一个或外部的循环,如下代码片段所示:

  'outer: loop { println!("进入外层地牢。"); inner: loop { println!("进入内层地牢。"); // break;    // 这将退出内层循环break 'outer; // 跳转到外层循环 } println!("这宝藏永远无法到达。"); } println!("已退出外层地牢!");  

这将打印以下输出:

进入外层地牢。
进入内层地牢。
已退出外层地牢!

显然,使用标签会使代码阅读更困难,因此请谨慎使用。幸运的是,Rust 中不存在 C 语言中臭名昭著的 goto 语句!

使用 for 循环和范围表达式可以完成从起始值 a 到结束值 b(不包括 b)的变量 var 的循环,如以下语句所示:

for var in a..b 

以下是一个打印数字 1 到 10 的平方的示例:

for n in 1..11 { println!("{} 的平方是 {}", n, n * n); 
}  

一般来说,for 循环遍历一个迭代器,即逐个返回一系列值的对象。范围 a…b 是最简单的迭代器形式。

每个后续的值都绑定到变量 n 并在下一个循环迭代中使用。当没有更多的值时,for 循环结束,并且变量 n 随之离开作用域。如果我们在循环中不需要变量 n 的值,可以用 _(下划线)替换,如下所示:

for _ in 1..11 { } 

C 风格 for 循环中的许多错误,如计数器的越界错误,在这里不会发生,因为我们是在遍历一个迭代器。

变量也可以用在范围中,如以下片段所示,它打印九个点:

let mut x = 10; 
for _ in 1..x { x -= 1; print!("."); }  

函数

每个 Rust 程序的起点都是一个名为 main() 的函数,它可以进一步细分为单独的函数,以便代码重用或更好地组织代码。Rust 不在乎这些函数的定义顺序,但将 main() 函数放在代码的开头是个好习惯,因为这样可以更好地概览代码结构。Rust 吸收了许多传统函数式语言的特性;我们将在高阶函数与错误处理* 中看到这方面的例子。

让我们从一个基础函数示例开始:

fn main() { let hero1 = "吃豆人"; let hero2 = "里迪克"; greet(hero2); greet_both(hero1, hero2); 
} fn greet(name: &str) { println!("嗨,伟大的{},你来这里是为了什么?", name); 
} fn greet_both(name1: &str, name2: &str) { greet(name1); greet(name2); 
}  

这将输出以下内容:

嗨,伟大的里迪克,你来这里是为了什么?嗨,伟大的吃豆人,你来这里是为了什么?嗨,伟大的里迪克,你来这里是为了什么?

像变量一样,函数具有必须唯一的变量 snake_case 名称,其参数(必须进行类型化)用逗号分隔,如此示例所示:

name1: &str, name2: &str 

它看起来像一个绑定,但没有 let 绑定。强制对参数进行类型化是一个优秀的设计决策,因为它为函数的调用代码提供了文档,并允许在函数内部进行类型推断。这里的类型是 &str,因为字符串存储在堆上

上面的函数没有返回任何有用的东西(事实上,它们返回单位值()),但如果我们希望一个函数实际返回一个值,其类型必须在箭头 -> 之后指定,如此示例所示:

fn increment_power(power: i32) -> i32 { println!("我的力量将会增加:"); power + 1 
} fn main() { 
let power = increment_power(1); // 调用函数 
println!("我现在的力量等级是:{}", power);}  

执行时,它打印出如下输出:

我的力量将会增加:
我现在的力量等级是:2 

函数的返回值是其最后一个表达式的值。请注意,为了返回一个值,最后一个表达式不得以分号结束。如果你以分号结束会发生什么?试试看:在这种情况下会返回单位值(),编译器会给你以下错误:

error: not all control paths return a value  

我们可以写 return power + 1 作为最后一行,但那并不是惯用代码。如果我们想要在最后一行代码之前从函数返回一个值,我们必须写 return value; 如下所示:

if power < 100 { return 999 } 

如果这是函数中的最后一行,你应该这样写:

if power < 100 { 999 } 

一个函数只能返回一个值,但这并不是一个很大的限制。例如,如果我们有三个值 a、b 和 c 要返回,就用一个元组 (a, b, c) 将它们组合起来并返回。我们将在下一章更详细地检查元组。

一个从不返回的函数称为发散函数,它的返回类型是 !。

例如:

fn diverges() -> ! { panic!("这个函数永远不返回!"); 
}  

它可以用作任何类型,例如用于隔离异常处理,如此示例所示。

一个函数可以是递归的;这意味着该函数调用自身,如下示例所示:

fn main() { let ans = fib(10); println!("{}", ans); 
} fn fib(x: i64) -> i64 { if x == 0 || x == 1 { return x; } fib(x - 1) + fib(x - 2) 
}  

确保递归停止通过包括一个基本情况,在这个例子中,当函数被调用 x 等于 1 和 0 时。

函数有类型,例如,之前代码片段中函数 increment_power 的类型如下:

Fn(i32) -> i32 

fn 函数通常表示一个函数类型。

在 Rust 中,你也可以在另一个函数内部写一个函数(称为嵌套函数),这与 C 或 Java 不同。这应该只用于本地需要的小型辅助函数。

作为练习,尝试以下操作:

了解到 if 可以是一个表达式,简化以下函数:

fn verbose(x: i32) -> &'static str { let result: &'static str; if x < 10 { result = "小于 10"; } else { result = "10 或更多"; } return result; 
}  

参见第3章\exercises\ifreturn.rs 中的代码。

静态的 in 和 static str 变量是所谓的生命周期指示,需要在这里指示函数返回值将存在多久。静态生命周期是可能的最长生命周期,这样的对象在整个应用程序中存活,并且在其所有代码中都可用。

这个返回给定数字变量 x 的绝对值的函数有什么问题?

fn abs(x: i32) -> u32 { if x > 0 { x } else { -x } } 

更正并测试它(参见第3章/exercises/absolute.rs 中的代码)。

文档化一个函数

让我们展示一个文档化代码的例子。在 exdoc.rs 文件中,我们如下文档化了一个名为 cube 的函数:

fn main() { println!("4 的立方是 {}", cube(4)); 
} 
/// 计算立方 `val * val * val`。 
/// 
/// # 示例 
/// 
/// ```
/// let cube = cube(val); 
/// ```
pub fn cube(val: u32) -> u32 { val * val * val 
}  

如果我们现在在命令行上调用 rustdoc exdoc.rs,将会创建一个 doc 文件夹。对于一个项目,请在项目的根文件夹中执行 cargo.doc。这将包含一个子文件夹 exdoc,其中有一个 index.html 文件,这是一个网站的起点,为每个函数提供文档页面。例如,fn.cube.html 显示如下内容:

  • 文档会详细介绍 cube 函数,包括它的定义、用途、示例代码等。
  • 页面会以友好和清晰的格式展示所有相关信息,使开发者能够快速理解和使用 cube 函数。

Rustdoc 是一个非常强大的工具,它可以自动生成代码的文档。这对于保持项目的文档最新且易于理解非常有帮助。通过在代码中包含适当的注释,Rustdoc 能够创建详尽的文档,这在大型项目或公共库中尤其重要。通过这种方式,即使是新加入项目的开发者也可以快速了解代码的工作方式和目的。

img

点击 exdoc 链接会返回到索引页面。

文档注释是用 Markdown 编写的(简要介绍见 https://en.wikipedia.org/wiki/Markdown)。它们可以包含由 # 预先的特殊部分。例子包括 Panics、Failures 和 Safety。代码放在 ```之间。要被文档化的函数必须属于公共接口,因此必须以 pub 为前缀。

可以使用 //! 注释来文档化模块,这些注释在初始 { 之后开始。

更多信息请见 https://doc.rust-lang.org/book/first-edition/documentation.html。

属性

在编译器中,你可能已经看到了像 #[warn(unused_variables)] 这样的警告示例。这些是属性,代表了关于代码的元数据信息。你可以在代码中自己使用它们,它们被放置在它们要说明的项目(比如一个函数)之前。例如,它们可以禁用某些类别的警告、打开某些编译器功能,或标记函数作为单元测试或基准测试代码的一部分。

条件编译

如果你想要一个函数只在特定的操作系统上工作,那么用 #[cfg(target_os = “xyz”)] 属性来标注它(其中 xyz 可以是 “windows”、“macos”、“linux”、“android”、“freebsd”、“dragonfly”、“bitrig” 或 “openbsd” 中的一个)。例如,下面的代码在 Windows 上运行正常:

fn main() { on_windows(); 
} #[cfg(target_os = "windows")] 
fn on_windows() { println!("这台机器的操作系统是 Windows。") 
}  

这会产生以下输出:

这台机器的操作系统是 Windows。  

如果我们尝试在 Linux 机器上构建这段代码,我们会得到以下错误:

error: unresolved name `on_windows  

这段代码甚至无法在 Linux 上构建,因为属性阻止了它!此外,你甚至可以制作你自己的自定义条件,详见 http://rustbyexample.com/attribute/cfg/custom.html。

属性也在测试和基准测试代码时使用。

测试

我们可以用 #[test] 属性前缀一个函数,以表明它是我们应用程序或库的单元测试的一部分。然后我们用以下命令编译并运行生成的可执行文件:

rustc --test program.rs

这将用测试运行器替换 main() 函数,并显示用 #[test] 标记的函数的结果,例如:

fn main() { println!("No tests are compiled,compile with rustc --test! "); 
} #[test] 
fn arithmetic() { if 2 + 3 == 5 { println!("You can calculate!"); } 
} 

测试函数,像示例中的 arithmetic(),是黑盒子,它们没有参数或返回值。当这个程序在命令行上运行时,它会产生以下输出:img

但是,如果我们将测试改为 if 2 + 3 == 6,测试同样会通过!试试看。事实证明,当测试函数的执行没有导致崩溃(在 Rust 术语中称为 panic)时,它们总是通过的,只有在发生 panic 时才会失败。这就是为什么测试(或调试)必须使用 assert_eq! 宏(或其他类似的宏),如下面的代码所示:

assert_eq!(2, power); 

这个语句测试变量 power 是否具有值 2。如果是,什么也不会发生,但如果 power 不等于 2,就会发生异常并使程序 panic,产生以下命令:

 thread '<main>' panicked at 'assertion failed.

在我们的第一个函数中,我们会写测试 assert_eq!(5, 2 + 3);,这会通过。

我们也可以使用 assert! 宏,以 assert!(2 + 3 == 5); 的形式写。如果括号内的表达式为真,这个宏什么也不做,但如果表达式为假,它会发生 panic。

这些宏在普通代码中也很有用,用于确保满足特定条件。只需注意,当它们失败时,它们是在程序运行时发生的!

当函数发生 panic 时,测试失败,如以下示例所示:

#[test] 
fn badtest() { assert_eq!(6, 2 + 3); 
}  

这会产生以下输出:

img

如果你想确保一个测试失败,请使用 #[should_panic] 属性,像这样:

#[test] 
#[should_panic(expected = "assertion failed")] 
fn failing_test() { assert!(6 == 2 + 3); 
}  

在这个例子中,failing_test 通过了,因为这是我们所期望的!我们最好添加 expected = "assertion failed" 文本,以确保 panic 是由断言失败引起的。

你可以通过给它额外的 #[ignore] 属性来禁用一个测试。

通过的测试以绿色显示,失败的测试以红色显示。

通过使用宏调用 assert_eq!(actual, expected) 将实际函数结果与预期结果进行比较来对你的函数进行单元测试。因此,考虑如下的一个函数:

pub fn double(n: i32) -> i32 { n * 2 
}  

它是这样被测试的:

assert_eq!(double(42), 84); 

pub 表示 double 是一个公共方法,可以被使用我们库的客户端代码调用。普通的私有方法不应该被显式测试,它们应该通过调用测试它们的公共方法来检查。

如果你不使用 test 属性编译,比如以下命令:

rustc attributes_testing.rs

没有测试函数被编译,当运行时 main() 函数会执行,在我们的例子中会打印以下输出:

No tests are compiled, compile with rustc --test!  

在正常构建中不包括测试代码。

在真实项目中,测试将被放在一个单独的测试模块中

使用 cargo 进行测试

一个可执行项目,或者在 Rust 中称为 crate,需要有一个启动函数 main(),但是一个库 crate,用于其他 crate,不需要 main() 函数。如下使用 cargo 创建一个新的库 crate mylib:

cargo new mylib

这将创建一个包含以下内容的源文件 lib.rs 的子文件夹 src:

#[cfg(test)] 
mod tests { #[test] fn it_works() { } 
}  

因此,创建了一个没有自己代码的库 crate,但它包含一个用 cfg(test) 属性注释的测试模板。这个属性表明,接下来的代码只会在测试模式下编译。为了与普通库代码区分开来,使用像这样的前缀 not 在属性中:

#[cfg(not(test))] 
fn main() { println!("正常模式,没有编译测试"); 
}  

在测试部分,你可以添加你对库函数编写的单元测试。要运行这些测试,请转到项目根文件夹并输入 cargo test,这将产生与前一节类似的输出。

你可以通过提供其函数名称来运行单个测试,像这样:

cargo test it_works  

命令 cargo test 尽可能并行运行测试。如果这可能造成问题,比如一个测试依赖于另一个测试,你可以使用以下命令在一个线程中执行它们所有:

cargo test -- --test-threads=1  

测试模块

在更现实、更大型的项目中,测试与应用程序代码是分开的:

  • 单元测试被收集在一个模块 test 中
  • 集成测试被收集在 tests 目录的 lib.rs 文件中

Cargo 为库生成的代码将测试分组到一个称为 mod tests 的模块内

为了使用主代码中定义的函数,我们必须添加命令 use super::*;,这会将所有这些函数带入测试模块的范围内:

pub fn double(n: i32) -> i32 { n * 2 
} #[cfg(test)] 
mod tests { use super::*; #[test] fn it_works() { assert_eq!(double(42), 84); } 
}  

模块 tests 通常用来包含你的库函数的单元测试。

使用函数和控制结构 中的 cube 函数作为另一个例子,使用 cargo 新建项目:cargo new cube。我们用以下代码替换 src\lib.rs 中的代码:

pub fn cube(val: u32) -> u32 { val * val * val 
} #[cfg(test)] 
mod tests;  

在第二行,我们用测试配置属性先声明我们的测试模块。现在这个模块的代码放到同一个文件夹下的 tests.rs 文件中,这样它们就可以更清晰地与我们的库代码分开:

use super::*; #[test] 
fn cube_of_2_is_8() { assert_eq!(cube(2), 8); 
} 

集成测试放在 tests 文件夹中的 lib.rs 文件中,我们需要手动创建它:

extern crate cube; 
use cube::cube; #[test] 
fn cube_of_4_is_64() { assert_eq!(cube(4), 64); 
} 

这里,我们需要用 extern 命令导入 cube crate,并用它的模块名 cube 来限定函数名 cube(或者使用 use cube::cube;)。

像之前一样,测试代码只有在我们给出 cargo test 命令时才会被编译和运行,结果如下:

img

我们看到我们的两个测试(单元测试和集成测试)都通过了。输出结果显示,如果文档中存在测试,它们也会在最后执行。

如果你想要能够使用像 describeit 这样的更类似 Speclike 框架的关键词,你肯定应该看看 stainless crate (https://github.com/reem/stainless)。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

《汇编语言:基于linux环境》补码研究

刚开始我使用&#xff0c;如下命令编译&#xff0c;链接程序。 nasm -f elf64 -g -F stabs sandbox.asmld -o sandbox sandbox.ogdb sandbox当我运行 sandbox 时&#xff0c;它会正常运行&#xff0c;但 gdb 无法显示任何源代码。为什么&#xff1f;当我在 gdb 中尝试 run 时&a…

鸿蒙(ArkUI)开发:实现二级联动

场景介绍 列表的二级联动&#xff08;Cascading List&#xff09;是指根据一个列表&#xff08;一级列表&#xff09;的选择结果&#xff0c;来更新另一个列表&#xff08;二级列表&#xff09;的选项。这种联动可以使用户根据实际需求&#xff0c;快速定位到想要的选项&#…

粒子群优化算法(Particle Swarm Optimization,PSO)求解基于移动边缘计算的任务卸载与资源调度优化(提供MATLAB代码)

一、优化模型介绍 移动边缘计算的任务卸载与资源调度优化原理是通过利用配备计算资源的移动无人机来为本地资源有限的移动用户提供计算卸载机会&#xff0c;以减轻用户设备的计算负担并提高计算性能。具体原理如下&#xff1a; 任务卸载&#xff1a;移动边缘计算系统将用户的计…

Windows11搭建GPU版本PyTorch环境详细过程

Anaconda安装 https://www.anaconda.com/ Anaconda: 中文大蟒蛇&#xff0c;是一个开源的Python发行版本&#xff0c;其包含了conda、Python等180多个科学包及其依赖项。从官网下载Setup&#xff1a;点击安装&#xff0c;之后勾选上可以方便在普通命令行cmd和PowerShell中使用…

BGP同步规则

BGP同步规则&#xff1a;开启同步下&#xff0c;从IBGP收到一条路由不会传给任何EBGP邻居(实验效果IBGP邻居和EBGP邻居都不传)&#xff0c;除非从自身的IGP中也学到这条路由。目的是防止AS内部出现路由黑洞&#xff0c;向外部通告了一个本AS不可达的虚假的路由。 同步规则只影响…

qt学习:http+访问百度智能云api实现车牌识别

目录 登录到百度智能云&#xff0c;找到文字识别 完成操作指引 开通 查看车牌识别的api文档 ​编辑​编辑 查看自己应用的api key 查看回应的数据格式 编程步骤 ui界面编辑 添加模块&#xff0c;头文件和定义变量 新建两个类&#xff0c;一个图像Image类&#xff0c…

Day01-变量和数据类型课后练习(输出你最想说的一句话,定义所有基本数据类型的变量和字符串变量,用合适类型的变量存储个人信息并输出,定义圆周率PI,简答题)

参考答案博客链接跳转 文章目录 1、输出你最想说的一句话&#xff01;2、定义所有基本数据类型的变量和字符串变量3、用合适类型的变量存储个人信息并输出4、定义圆周率PI5、简答题 1、输出你最想说的一句话&#xff01; 编写步骤&#xff1a;List item定义类 Homework1&…

【嵌入式移植】5、U-Boot源码分析2—make nanopi_neo2_defconfig

U-Boot源码分析2—make nanopi_neo2_defconfig 1 概述2 nanopi_neo2_defconfig3 编译过程分析3.1 编译目标3.2 scripts_basic3.2.1 prefix src定义3.2.2 PHONY3.2.3 __build3.2.4 fixdep3.3 objscripts/kconfig 1 概述 上一章中&#xff0c;对Makefile相关源码进行了初步分析&…

从零开始:CentOS系统下搭建DNS服务器的详细教程

前言 如果你希望在CentOS系统上建立自己的DNS服务器,那么这篇文章绝对是你不容错过的宝藏指南。我们提供了详尽的步骤和实用技巧,让你能够轻松完成搭建过程。从安装必要的软件到配置区域文件,我们都将一一为你呈现。无论你的身份是运维人员,还是程序员,抑或是对网络基础设…

服务端开发小记02——Maven

这里写目录标题 Maven简介Maven在Linux下的安装Maven常用命令 Maven简介 Apache Maven Project是一个apache的开源项目&#xff0c;是用于构建和管理Java项目的工具包。 用Maven可以方便地创建项目&#xff0c;基于archetype可以创建多种类型的java项目&#xff1b;Maven仓库…

5G_RACH(一)

什么是RACH RACH 代表 Random Access Channel。这是开机时UE发给eNB的第一条消息。 为什么选择RACH &#xff1f;&#xff08;RACH 的功能是什么&#xff1f; 当你第一次听到RACH或RACH Process这个词时&#xff0c;你脑海中浮现的第一个问题是“为什么是RACH&#xff1f;”…

05 Redis之Benchmark+简单动态字符串SDS+集合的底层实现

3.8 Benchmark Redis安装完毕后会自动安装一个redis-benchmark测试工具&#xff0c;其是一个压力测试工具&#xff0c;用于测试 Redis 的性能。 src目录下可找到该工具 通过 redis-benchmark –help 命令可以查看到其用法 3.8.1 测试1 3.9 简单动态字符串SDS 无论是 Redis …

网络通信实现

【 一 】网络通信实现 【 1 】实现网络通信的四要素 本机的ip地址 子网掩码 网关的IP地址 DNS的IP地址( 域名系统) DNS服务器是指提供域名解析服务的服务器。它负责将域名转换为相应的IP地址&#xff0c;以便计算机可以通过IP地址与其他设备进行通信。 通过使用DNS服务器…

【C语言】linux内核ipoib模块 - ipoib_netdev_ops_pf结构

一、ipoib_netdev_ops_pf结构 static const struct net_device_ops ipoib_netdev_ops_pf {.ndo_init ipoib_ndo_init,.ndo_uninit ipoib_ndo_uninit,.ndo_open ipoib_open,.ndo_stop ipoib_stop,.ndo_change_mtu ipoib_change_mtu,.ndo_…

java servlet勤工助学家教管系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 java servlet 勤工助学家教管系统是一套完善的java web信息管理系统 serlvetdaobean mvc 模式开发 &#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myecli…

绝地求生:【PC】开发者日志:竞技比赛地图轮换

各位玩家大家好&#xff0c;欢迎收看闲游盒本期开发者日志。 今天闲游盒想和大家分享一下2024年竞技比赛地图轮换的几项主要改动。 从第28赛季第1轮更新&#xff08;2月&#xff09;开始&#xff0c;竞技比赛的地图阵容中将包含所有8x8尺寸的地图&#xff0c;在电竞赛事中出场…

SpringBoot-yml文件的配置与读取

配置 值前边必须要有空格&#xff0c;作为分隔符 使用空格作为缩进表示层级关系&#xff0c;相同的层级左侧对齐 获取 使用Value(”${键名}”) 使用ConfigurationProperties(prefix "前缀") 1.前缀要与yml配置文件中的前缀一致 2.实体类的字段名与配置文件中的键名一…

【微服务】springboot集成ELK使用详解

目录 一、前言 二、为什么需要ELK 三、ELK介绍 3.1 什么是elk 3.2 elk工作原理 四、ELK环境搭建 4.1 搭建es环境 4.1.1 获取es镜像 4.1.2 启动es容器 2.1.3 配置es参数 2.1.4 重启es容器并访问 4.2 搭建kibana 4.2.1 拉取kibana镜像 4.2.2 启动kibana容器 4.2.3 …

GitLab16.8配置webhooks、Jenkins2.4配置GitLab插件实现持续集成、配置宝塔面板实现持续部署

看本篇文章的前提是已经部署完GItlab和Jenkins服务器&#xff0c;已经可以手动构建成功&#xff0c;并且经过了很多次实践&#xff0c;对这两款软件基本熟悉。 建议大家按以下顺序看 前端自动化&#xff08;其一&#xff09;部署gitlab https://blog.csdn.net/weixin_45062076…

【Redis】Redis集群方案应该怎么做 都有哪些方案

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a;Redis ⛳️ 功不唐捐&#xff0c;玉汝于成 目录 前言 正文 &#xff08;1&#xff09;twemproxy &#xff08;2&#xff09;codis &#xff08;3&#xff09;redis cluster3.0自带的集群 …