Rust循环和函数

news2024/10/7 0:27:52

下面聊聊以下主题:

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

基于条件的分支

基于条件的分支,可以通过常见的 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.coloradmin.cn/o/1418212.html

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

相关文章

JVM问题排查手册

三万字长文&#xff1a;JVM内存问题排查Cookbook 一、Heap快照 # jmap命令保存整个Java堆&#xff08;在你dump的时间不是事故发生点的时候尤其推荐&#xff09; jmap -dump:formatb,fileheap.bin <pid> # jmap命令只保存Java堆中的存活对象, 包含live选项&#xff0c;…

golang:beego的简单介绍和TiDB数据库的客户端实现

查阅官方文档和源码可以知道&#xff0c;beego库中有一个orm包负责数据库接口的封装。这个包支持若干个数据库引擎&#xff1a; 看到了一个文档&#xff0c;对ORM(Object-Relational Mapping)这个东西解释得比较清楚&#xff1a; 具体的客户端实现见下&#xff1a; package …

【JavaScript基础入门】04 JavaScript基础语法(二)

JavaScript基础语法&#xff08;二&#xff09; 目录 JavaScript基础语法&#xff08;二&#xff09;变量变量是什么声明变量变量类型动态类型注释 数字与运算符数字类型算术运算符操作运算符比较运算符逻辑运算符运算符的优先级 变量 变量是什么 在计算机中&#xff0c;数据…

Cesium 问题:遇到加载Cesium时各组件飞出

致敬爱的读者&#xff1a;该问题出现后暂时未找到最优的解决方案&#xff0c;而是将所有组件状态均进行隐藏&#xff0c;大家如果有解决方案可以留言、评论大家一起探讨解决&#xff0c;欢迎大家踊跃说出自己的想法 文章目录 问题分析 问题 在加载 Cesium 时出现各组件的位置不…

HarmonyOS模拟器启动失败,电脑蓝屏解决办法

1、在Tool->Device Manager管理界面中&#xff0c;通过Wipe User Data清理模拟器用户数据&#xff0c;然后重启模拟器&#xff1b;如果该方法无效&#xff0c;需要Delete删除已创建的Local Emulater。 2、在Tool->SDK Manager管理界面的PlatForm选项卡中&#xff0c;取消…

云畅科技入选国家超级计算长沙中心生态合作伙伴

为更好地服务国家战略和区域经济社会高质量发展&#xff0c;打造数据驱动经济发展的新态势&#xff0c;国家超级计算长沙中心面向全国开展了生态合作伙伴的征集工作。经企业申报、专家评审等环节&#xff0c;湖南云畅网络科技有限公司顺利通过审核&#xff0c;成功入选“国家超…

面试经典150题——找出字符串中第一个匹配项的下标

找出字符串中第一个匹配项的下标 思路分析&#xff1a; 思路一&#xff1a;直接调用String的API&#xff1a;indexOf 大道至简&#xff0c;String中的IndexOf是这样描述的&#xff1a; /*** Returns the index within this string of the first occurrence of the* specified…

牛客——小红又战小紫(概率dp和逆元)

链接&#xff1a;登录—专业IT笔试面试备考平台_牛客网 来源&#xff1a;牛客网 小红上次输给了小紫&#xff0c;表示不服&#xff0c;于是又约来小紫来玩一个游戏。 这次是取石子游戏&#xff1a;共有nnn堆石子&#xff0c;两人轮流使用以下两种技能中的一种进行取石子&#x…

如何在Win系统安装Jupyter Notbook并实现无公网ip远程访问本地笔记

文章目录 1.前言2.Jupyter Notebook的安装2.1 Jupyter Notebook下载安装2.2 Jupyter Notebook的配置2.3 Cpolar下载安装 3.Cpolar端口设置3.1 Cpolar云端设置3.2.Cpolar本地设置 4.公网访问测试5.结语 1.前言 在数据分析工作中&#xff0c;使用最多的无疑就是各种函数、图表、…

《WebKit 技术内幕》学习之十四(1):调式机制

第14章 调试机制 支持调试HTML、CSS和JavaScript代码是浏览器或者渲染引擎需要提供的一项非常重要的功能&#xff0c;这里包括两种调试类型&#xff1a;其一是功能&#xff0c;其二是性能。功能调试能够帮助HTML开发者使用单步调试等技术来查找代码中的问题&#xff0c;性能调…

【漏洞复现】零视技术H5S视频平台信息泄漏漏洞

Nx01 产品简介 零视技术(上海)有限公司是以领先的视频技术服务于客户&#xff0c;致力于物联网视频开发简单化&#xff0c;依托于HTML5 WebRTC 等新的技术&#xff0c;实现全平台视频播放简单化。 Nx02 漏洞描述 零视技术(上海)有限公司H5S CONSOLE存在未授权访问漏洞&#xf…

ElasticSearch重建/创建/删除索引操作 - 第501篇

历史文章&#xff08;文章累计500&#xff09; 《国内最全的Spring Boot系列之一》 《国内最全的Spring Boot系列之二》 《国内最全的Spring Boot系列之三》 《国内最全的Spring Boot系列之四》 《国内最全的Spring Boot系列之五》 《国内最全的Spring Boot系列之六》 E…

在WSL2中利用gradle构建项目时出现:Could not connect to the Gradle daemon. 的解决方案

最近本人在做基于expo开发的某个APP&#xff0c;由于某种原因&#xff0c;eas云构建连接不上&#xff08;卡在连接谷歌那一步&#xff09;&#xff0c;于是想要利用官方提供的本地构建功能在本地构建一下&#xff0c;结果在wsl这里摔了个跟头&#xff09;&#xff09; eas要求必…

WSL—子系统安装及其相关配置和[诸多报错问题]-修改默认安装位置

一、WSL简介 WSL的全称是Windows Subsystem for Linux。 适用于 Linux 的 Windows 子系统可让开发人员按原样运行 GNU/Linux 环境 - 包括大多数命令行工具、实用工具和应用程序 - 且不会产生传统虚拟机或双启动设置开销。 二、开启WSL功能 系统要求&#xff1a;win10/11 专业…

前端Vue v-for 的使用

目录 ​编辑 简介 使用方式 基本使用 v-for"(item, index)中item和index作用 示例 迭代对象 示例 结果 前言-与正文无关 生活远不止眼前的苦劳与奔波&#xff0c;它还充满了无数值得我们去体验和珍惜的美好事物。在这个快节奏的世界中&#xff0c;我们往往容易陷入…

数据可视化工具JSON Crack结合内网穿透实现公网访问

文章目录 1. 在Linux上使用Docker安装JSONCrack2. 安装Cpolar内网穿透工具3. 配置JSON Crack界面公网地址4. 远程访问 JSONCrack 界面5. 固定 JSONCrack公网地址 JSON Crack 是一款免费的开源数据可视化应用程序&#xff0c;能够将 JSON、YAML、XML、CSV 等数据格式可视化为交互…

超级好用的远程控制APP!!!

在这个科技日新月异的时代&#xff0c;我们的生活被各种手机软件所包围。几乎每个人都有一个甚至多个手机&#xff0c;你是否也有遇到过需要远程操作自己某一台手机的场景呢&#xff1f;今天&#xff0c;我要向大家推荐一款神奇的手机远程操作神器&#xff0c;让你可以随时随地…

Springboot的 Lombok全部关联注解以及核心注解@Data详解

目录 工具安装 依赖注入 注解类别 1. Getter / Setter 2. ToString 3. EqualsAndHashCode 4. NoArgsConstructor / RequiredArgsConstructor / AllArgsConstructor 5. Data 示例 注意事项 6. Value 7. Builder 8. Slf4j / Log / Log4j / Log4j2 / XSlf4j 9. NonN…

【音视频原理】音频编解码原理 ③ ( 音频 比特率 / 码率 | 音频 帧 / 帧长 | 音频 帧 采样排列方式 - 交错模式 和 非交错模式 )

文章目录 一、音频 比特率 / 码率1、音频 比特率2、音频 比特率 案例3、音频 码率4、音频 码率相关因素5、常见的 音频 码率6、视频码率 - 仅做参考 二、音频 帧 / 帧长1、音频帧2、音频 帧长度 三、音频 帧 采样排列方式 - 交错模式 和 非交错模式1、交错模式2、非交错模式 一…

【网络】:网络套接字(UDP)

网络套接字 一.网络字节序二.端口号三.socket1.常见的API2.封装UdpSocket 四.地址转换函数 网络通信的本质就是进程间通信。 一.网络字节序 我们已经知道,内存中的多字节数据相对于内存地址有大端和小端之分, 磁盘文件中的多字节数据相对于文件中的偏移地址也有大端小端之分,网…