一网打尽 Rust 语法

悲观者永远正确,而乐观者永远前行

大家好,我是「柒八九」。一个「专注于前端开发技术/RustAI应用知识分享」Coder

前言

在之前的Rust学习专栏中,由于受制与文章的脉络,我们只能从概念到使用场景进行事无巨细的解释。相当于一篇文章介绍一种概念。

alt

但是呢,这种处理方式只是在阅读某个文章时有种豁然开朗的感觉,但是无法从更高的视角去整体把握Rust的一些数据特性。(这也是部分粉丝的提出的一些建议)

所以,今天我们抛开历史包袱,只是单纯的从Rust的角度来窥探一下Rust中的数据类型到底有哪些。(放心,我们会在特定的位置,将附带更详细的文章链接)。

这篇文章没啥原理可言,我们可以将其作为我们以后学习和开发Rust的工具手册。

好了,天不早了,干点正事哇。

alt

我们能所学到的知识点

  1. 构建运行环境
  2. 变量类型
  3. 操作数组
  4. 操作字符串
  5. 操作向量
  6. 函数
  7. 输入/输出
  8. Shadowing
  9. 控制块
  10. 循环
  11. 所有权
  12. 结构体
  13. 枚举
  14. 并发

1. 构建运行环境

我们在Rust环境配置和入门指南中详细介绍了

  • 如何安装 Rust环境
  • 构建一个 Rust应用
  • 编译和运行的区别
  • 使用 Cargo构建 Rust应用

下面,我们就之间直入主题了。

通过创建一个名为 main.rs 的文件并将以下代码放入其中来编写我们的第一个 Rust 代码:

fn main() {
    println!("Hello, Front789!");
}

然后通过运行 rustc main.rs./main.exe 来运行这个程序,就像运行 C 程序一样。

CargoRust 的构建系统和包管理器

我们也可以使用 cargo 创建项目。

  • cargo new hello_cargo:初始化一个新项目。
  • cargo build:构建一个 cargo 项目。
  • cargo run:运行一个 cargo 项目,这将编译并运行代码。
  • cargo check:检查是否有编译错误,它比 cargo build速度更快。
  • cargo build --release:这将使用优化进行编译,用于最终生产构建。

2. 变量类型

Rust 中,默认情况下「变量是不可变」的,这意味着一旦给变量赋值,其值就不会改变。

所以如果想要一个可变的,即可改变的值,使用 mut

let a = 5;
let mut b = 5// 可变的
  • 整数:有各种大小的 有符号无符号整数(例如,i8、i16、i32、i64、u8、u16、u32、u64) alt
let number: i32 = 42;
  • 浮点数: 单精度双精度浮点数(例如,f32、f64) alt
let pi: f64 = 3.14159;
  • 布尔值: Rust的布尔类型只拥有两个可能的值 truefalse,它 「只会占据单个字节的空间大小」。使用 bool来表示一个布尔类型。
let is_rust_cool: bool = true;
  • 字符:在 Rustchar类型 「占4字节」,是一个 Unicode标量值,这意味着它可以表示比 ASCII多的字符内容。使用 char 类型表示一个字符类型
let heart_emoji: char = '❤';
  • 字符串:可变字符串 alt
let mut s = String::from("front789");
  • 字符串切片:不可变且借用的字符串切片
let s1: &str = "front789";
  • 数组:数组中每一个元素都必须是 「相同类型」Rust「数组拥有固定的长度,一旦声明就再也不能随意更改大小」
let array: [i323] = [123];
let a = [35]; // 用值 3 初始化大小为 5 的数组
  • 元组 alt
    • 为了从元组中获得单个的值,可以使用 「模式匹配」来解构元组
    • 还可以通过 「索引」并使用点号( .)来访问元组中的值
let tup = (5006.41);
let (x, y, z) = tup;
let aa = tup.0// 引用元组中的第一个项目
  • 向量 alt

  • 指针和引用

    • 指针是一个变量,它存储了一个值的 「内存地址」
    • Rust 中最常见的指针是 引用。引用以 & 符号为标志并 「借用了它们所指向的值」。除了引用数据没有任何其他特殊功能。它们也没有任何额外开销,所以应用得最多。
fn main() {
    // 标量类型
    let number: i32 = 42;
    let pi: f64 = 3.14159;
    let is_rust_cool: bool = true;
    let heart_emoji: char = '❤';

    // 复合类型
    let array: [i323] = [123];
    let tuple: (i32f64char) = (103.14'a');
    let slice: &[i32] = &[123];
    let string: String = String::from("Hello, Front789!");
    let string_slice: &str = "Hello, Front789!";

    // 特殊类型
    let reference_to_number: &i32 = &number;
    let optional_value: Option<i32> = Some(42);
    let result_value: Result<i32, &str> = Ok(42);
}

以上内容就是Rust中所涉及到的各种数据类型,我们可以从以下的链接中找到更为详细的解释

  • 基础概念
  • 集合
  • 智能指针

3. 操作数组

不可变数组:

不可变数组在 Rust 中用 [T; N] 语法来声明,其中 T 表示数组元素的类型,而 N 表示数组的长度。

对于不可变数组,我们可以使用下标访问其元素,但不能修改元素的值。

let array = [12345];
let first_element = array[0]; // 访问第一个元素
arr[0] = 6// 这行代码会导致编译错误,因为数组是不可变的

// 迭代
// 使用 for 循环
for &num in &array {
    println!("{}", num);
}
// 另一种迭代器
array.iter().for_each(|&num| {
    println!("{}", num);
});

let slice = &array[1..3]; // 从索引 1 到索引 2(包括)切片

可变数组

Vec<T> Rust 中可变长数组的实现,它允许您动态地增加或减少数组的大小。

let mut array = [12345];
array[0] = 10// 修改第一个元素

let mut vec = Vec::new(); // 创建一个空 Vec
vec.push(1); // 向 Vec 中添加一个元素
vec.push(2);
vec.push(3);

// 使用 iter() 遍历元素

for item in array.iter() {
    println!("{}", item);
}

// iter_mut() 方法返回一个可变的迭代器,允许修改 Vec 中的元素
for item in array.iter_mut() {
    *item += 1// 对每个元素加 1
}

// map
let doubled_array: Vec<_> = 
    array.iter()
    .map(|&num| num * 2)
    .collect();

// filter
let even_elements: Vec<_> = 
    array.iter()
    .filter(|&&num| num % 2 == 0)
    .collect();

// len() 方法返回 Vec 中元素的数量
array.len()

// remove() 方法移除指定索引位置的元素,并返回该元素。如果索引越界,它将导致 panic。
let removed_item = array.remove(2// removed_item 为3

4. 操作字符串

let s1 = String::from("Hello, ");
let s2 = String::from("Front789!");
let combined = s1 + &s2; // 注意:s1 在这里被移动,之后不能再使用
println!("{}", combined); // 打印 "Hello, Front789!"

let mut s = String::from("Hello, ");
s.push_str("Front789!");
println!("{}", s); // 打印 "Hello, Front789!"

// 获取字符
let s = String::from("hello");
let first_char = s.chars().nth(0); // 访问第一个字符

// 子字符串
let s = String::from("hello Front789");
let substring = &s[0..5]; // 提取 "hello"

// len()
let s = String::from("hello");
let length = s.len(); // 字符串的长度

// replace
let s = String::from("hello");
let replaced = s.replace("l""z"); // 替换 "l" 为 "z"

// split
let s = String::from("hello Front789");
let words: Vec<&str> = s.split_whitespace().collect(); // 分割成单词

// 转换 &str 和 String
let s = String::from("hello");
let s_ref: &str = &s; // 将 String 转换为 &str
let s_copy: String = s_ref.into(); // 将 &str 转换为 String

5. 操作向量

let mut v1 = vec![123]; // 使用 vec![] 宏
let mut v2: Vec<i32> = Vec::new(); // 使用 Vec::new() 构造函数

let mut v = Vec::new();
v.push(1);
v.push(2);

let first_element = v[0]; // 访问第一个元素

// 迭代
// 使用 for 循环
for num in &v {
    println!("{}", num);
}

// 使用迭代器
v.iter().for_each(|&num| {
    println!("{}", num);
});

// slice
let slice = &v[1..3]; // 从索引 1 到索引 2(包括)提取元素

// remove
let removed_element = v.remove(1); // 移除索引为 1 的元素(返回被移除的元素)

// sort()
v.sort();

// join
let tt= vec!["hello""Front789"];
let joined_string = tt.join(", "); // 使用逗号和空格连接元素

6. 函数

Rust代码使用「蛇形命名法」来作为规范函数和变量名称的风格。蛇形命名法「只使用小写的字母进行命名,并以下画线分隔单词」

  1. 参数,它们是一种 「特殊的变量,并被视作函数签名的一部分」。当函数存在参数时,你需要在 「调用函数时为这些变量提供具体的值」
  2. Rust中, 「函数的返回值等同于函数体的最后一个表达式」

语法

fn 函数名(参数1: 类型1, 参数2: 类型2) -> 返回类型 {
    // 函数体
    // 可选的表达式
}

最后一行返回值时不需要调用 return

fn add_numbers(x: i32, y: i32) -> i32 {
    let sum = x + y;
    sum // 函数中的最后一个表达式会隐式返回
}

如果想要一个无返回值的函数,不要定义返回类型。

我们可以在基础概念_函数部分查看更详细的解释


7. 输入/输出

输入

要读取一个值,使用 io stdin 并给出变量的值,在失败时需要提供 expect 消息,否则会出错。

let mut guess = String::new();    
io::stdin().read_line(&mut guess).expect("该行读取失败");

输出 / 打印

println!("输出对应的变量信息 {}", guess); // 这里的 guess 是变量名。

你也可以在末尾有变量

let y = 10;

println!("y + 2 = {}", y + 2);

8. Shadowing

Rust中,一个「新的声明变量可以覆盖掉旧的同名变量」,我们把这一个现象描述为:「第一个变量被第二个变量遮蔽Shadow了」。这意味着随后使用这个名称时,它指向的将会是第二个变量。

fn main() {
    let x = 5// 定义值为 5 的变量 x
    println!("原始值 x: {}", x); // 打印 "原始值 x: 5"
    
    let x = 10// Shadowing:定义一个新的值为 10 的变量 x
    println!("Shadowed x: {}", x); // 打印 "Shadowed x: 10"
}
alt

9. 控制块

alt

If else

if condition1 {
    // 如果 condition1 为真,则执行的代码
else if condition2 {
    // 如果 condition2 为真,则执行的代码
else {
    // 如果 condition1 和 condition2 都为假,则执行的代码
}

10. 循环

Rust提供了3种循环

  1. loop
  2. while
  3. for

loop

loop {
    println!("永无止境的执行");
}

While 循环

let mut count = 0;
while count < 5 {
    println!("Count: {}", count);
    count += 1;
}

For 循环

for i in 0..5 {
    println!("{}", i);
}

foreach

当然也少不了对数值的遍历操作。

(1..=5).for_each(|num| {
    println!("Number: {}", num);
});
// Number: 1
// Number: 2
// Number: 3
// Number: 4
// Number: 5

..:它表示一个扩展运算符,表示从第一个数字到最后一个数字生成。

我们也可以在循环中使用 continuebreak


11. 所有权

alt

这个概念是需要特别注意和反复观看的部分。

MOVE(或)重新分配变量

当变量值被重新分配时,值会给新的所有者,并且旧的所有者被丢弃。

这种行为在字符串中经常看到,而不是其他类型,如下所示:

let s1 = String::from("hello");
let s2 = s1;

println!("{}, world!", s1);

这将导致错误,因为 s1s2=s1 之后不再有效。

如何解决上面的问题呢,我们可以使用 Clone

let s1 = String::from("hello");
let s2 = s1.clone();

println!("s1 = {}, s2 = {}", s1, s2);

某些类型隐式实现了 Clone

let x = 5// x 拥有整数 5
let y = x; // 将 x 的值复制到 y,不传递所有权

例如,整数隐式实现了 Clone,因此这段代码不会报错。

alt

所有权和函数

fn main() {
    let s = String::from("hello");  // s 进入作用域

    takes_ownership(s);             // s 的值移动进入函数...
                                    // ... 所以这里不再有效

    let x = 5;                      // x 进入作用域

    makes_copy(x);                  // x 会移入函数,
                                    // 但 i32 是 Copy,所以在之后继续使用 x 是可以的

// 在这里,x 超出作用域,然后是 s。但因为 s 的值被移动了,所以没有什么特别的发生。

fn takes_ownership(some_string: String) { // some_string 进入作用域
    println!("{}", some_string);
// 在这里,some_string 超出作用域,调用 drop。内存被释放。

fn makes_copy(some_integer: i32) { // some_integer 进入作用域
    println!("{}", some_integer);
// 在这里,some_integer 超出作用域。没有什么特别的发生。

如果我们像在变量被移动后,继续使用,那么我们就使用 takes_ownership(s.clone()); (或者)在 takes_ownership 函数中返回值,像这样:

fn main() {
    let s2 = String::from("hello");     // s2 进入作用域
    let s3 = takes_and_gives_back(s2);  // s2 移入并被返回
}

fn takes_and_gives_back(a_string: String) -> String { 
    a_string  // 返回并移出到调用函数
}

借用 — 所有权

传递变量的引用,所有权不会被传递。

我们称「创建引用的操作为借用」。就像现实生活中,如果一个人拥有一样东西,你可以从他们那里借来。借了之后,你必须归还。你不拥有它。

fn main() {
    let s1 = String::from("hello");

    let len = calculate_length(&s1);

    println!("The length of '{}' is {}.", s1, len);
}

fn calculate_length(s: &String) -> usize {
    s.len()
}

针对此处更详细的内容,可以翻看我们之前的所有权


12. 结构体

struct,或者 structure,是一个「自定义数据类型」,允许我们命名和包装多个相关的值,从而形成一个有意义的组合。

alt
struct User {
    active: bool,
    username: String,
    email: String,
    sign_in_count: u64,
}

fn main() {
    let mut user1 = User {
        active: true,
        username: String::from("front789"),
        email: String::from("front789@example.com"),
        sign_in_count: 1,
    };

    user1.email = String::from("anotheremail@example.com");

    let user2 = User {
        email: String::from("another@example.com"),
        ..user1
    };
}

user2 中,你会看到 ..,它是扩展运算符,将 user1 中剩余的值传递给 user2(除了已经定义的 email)。

结构体的方法

使用 impl 结构体名,并在其中定义函数。

#[derive(Debug)]
struct Rectangle {
    width: u32,
    height: u32,
}

impl Rectangle {
    fn area(&self) -> u32 {
        self.width * self.height
    }
}

fn main() {
    let rect1 = Rectangle {
        width: 30,
        height: 50,
    };

    println!(
        "长方形的面积为 {}",
        rect1.area()
    );
}
alt

针对此处更详细的内容,可以翻看我们之前的结构体


13. 枚举

枚举,也被称作 enums。枚举允许你通过「列举可能的成员variants来定义一个类型」

enum IpAddrKind {
    V4,
    V6,
}

let four = IpAddrKind::V4;
let six = IpAddrKind::V6;

枚举的成员位于其标识符的「命名空间中」,并「使用两个冒号分开」

match

这是类似于 switch 的东西,

enum Coin {
    Penny,
    Nickel,
    Dime,
    Quarter,
}

fn value_in_cents(coin: Coin) -> u8 {
    match coin {
        Coin::Penny => 1,
        Coin::Nickel => 5,
        Coin::Dime => 10,
        Coin::Quarter => 25,
    }

    let number = 5;

    match number {
        1 => println!("One"),
        2 => println!("Two"),
        3 | 4 | 5 => println!("Three, Four, or Five"),
        _ => println!("Other"), // 默认情况
    }
}

每个分支相关联的代码是一个表达式,而表达式的结果值将作为整个 match 表达式的返回值。

Option 枚举和其相对于空值的优势

alt

if Let

这是一种使用 if 的花式方式,我们在其中定义一个表达式。

fn main() {
    let optional_number: Option<i32> = Some(5);

    // 使用 if let 匹配 Some 变体并提取内部值
    if let Some(num) = optional_number {
        println!("Value: {}", num);
    } else {
        println!("No value");
    }
}

14. 并发性

并发编程和并行编程

alt

代码实现

为了创建一个新线程,需要调用 thread::spawn 函数并「传递一个闭包」,并在其中包含希望在新线程运行的代码。

可以通过将 thread::spawn「返回值储存在变量中来修复新建线程部分没有执行或者完全没有执行的问题」thread::spawn 的返回值类型是 JoinHandleJoinHandle 是一个「拥有所有权的值」,当「对其调用 join 方法时,它会等待其线程结束」

use std::thread;

fn main() {
    // 数据
    let numbers = vec![12345678910];

    // 将数据分成两部分
    let mid = numbers.len() / 2;
    let (left, right) = numbers.split_at(mid);

    // 生成两个线程来计算每一半的总和
    let handle1 = thread::spawn(move || sum(left));
    let handle2 = thread::spawn(move || sum(right));

    // 等待线程完成并获取它们的结果
    let result1 = handle1.join().unwrap();
    let result2 = handle2.join().unwrap();

    // 计算最终总和
    let total_sum = result1 + result2;

    println!("Total sum: {}", total_sum);
}

fn sum(numbers: &[i32]) -> i32 {
    let mut sum = 0;
    for &num in numbers {
        sum += num;
    }
    sum
}

thread::spawn 要求闭包具有 'static 生命周期,这意味着它不会从周围范围借用任何东西,并且可以在整个程序的持续时间内存在。

因此,我们使用move 闭包,其经常与 thread::spawn 一起使用,因为它允许我们「在一个线程中使用另一个线程的数据」

针对此处更详细的内容,可以翻看我们之前的并发


后记

「分享是一种态度」

「全文完,既然看到这里了,如果觉得不错,随手点个赞和“在看”吧。」

alt

本文由 mdnice 多平台发布

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

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

相关文章

伪分布Hadoop下安装Hive

一、下载并安装Mysql &#xff08;1&#xff09;下载mysql安装包&#xff08;mysql-8.0.26-1.el7.x86_64.rpm-bundle.tar&#xff09; 下载官网&#xff1a;MySQL :: Download MySQL Community Server (Archived Versions)https://downloads.mysql.com/archives/community/ &…

【大模型书籍】从零开始大模型开发与微调:基于PyTorch与ChatGLM(附PDF)

哈喽各位&#xff0c;今天又来给大家分享大模型学习书籍了&#xff0c;今天是这本<从零开始大模型开发与微调&#xff1a;基于PyTorch与ChatGLM 书籍PDF分享>&#xff0c;大模型是深度学习自然语言处理皇冠上的一颗明珠&#xff0c;也是当前AI和NLP研究与产业中最重要的方…

解决IDEA中Tomcat控制台乱码问题(包括sout输出乱码)

文章目录 前言一、控制台直接输出乱码二、sout输出内容在控制台显示乱码 前言 今天在使用Tomcat的时候发现控制台输入出现了乱码问题&#xff0c;其实之前就出现过一次&#xff0c;解决了&#xff0c;但是新创建一个项目后又会出现sout的内容在控制台输出的乱码问题&#xff0…

【论文复现|智能算法改进】融合正余弦策略的算术优化算法

目录 1.算法原理2.改进策略3.结果展示4.参考文献 1.算法原理 【智能算法】算术优化算法&#xff08;AOA&#xff09;原理及实现 2.改进策略 基于适应度的自适应 MOA 策略 正弦余弦策略 3.结果展示 4.参考文献 [1] 黄学雨,罗华.融合正余弦策略的算术优化算法[J].计算机工…

分布式版本控制工具 Git 的使用方式

文章目录 Git简介下载安装基本使用起始配置Git 的三个区域基本操作流程查看仓库状态删除&#xff08;撤销暂存区&#xff09;差异对比查看版本日志版本回退修改提交日志分支概念&#xff1a;创建分支与切换分支合并分支&#xff08;快速合并&#xff09;合并分支&#xff08;提…

Linux的FTP服务

目录 1.什么是FTP服务&#xff1f; 2.FTP的工作原理和流程 1 主动模式 2 被动模式 3.搭建和配置FTP服务 1 下载服务包、备份配置文件 2 修改配置文件​编辑 3 匿名访问测试 4 设置黑白命令 1.什么是FTP服务&#xff1f; FTP&#xff08;file Transfer Protocol&#…

Java:二叉树(1)

从现在开始&#xff0c;我们进入二叉树的学习&#xff0c;二叉树是数据结构的重点部分&#xff0c;在了解这个结构之前&#xff0c;我们先来了解一下什么是树型结构吧&#xff01; 一、树型结构 1、树型结构简介 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>…

三角函数与其他复杂函数在C语言中的实现:CORDIC算法、泰勒公式、查表法与math库详解

在C语言中实现三角函数&#xff0c;通常有四种主要方法&#xff1a;CORDIC算法、泰勒公式展开、查表法以及直接调用C语言的标准数学库。接下来我们将详细介绍这四种方法&#xff0c;并探讨其他可能的补充实现手段。 1. CORDIC算法 CORDIC&#xff08;Coordinate Rotation Dig…

DDR3简介

文章目录 前言一、ddr_stress_tester_v2.90配置流程二、将inc配置文件下载到板子上1.连接方式2.打开DDR_Tester 软件 uboot中DDR初始化的修改 前言 &#x1f4a6;DDR3在自己做完板子后需要验证下&#xff0c;测试DDR3是否能正常使用&#xff0c;如果不能正常使用&#xff0c;其…

前缀和 求数列的子序列的K倍区间

(直接截图比复制文字要好多了) 不会做的时候我去看了之前做的关于这道题目的笔记&#xff0c; &#xff08;Ak 1&#xff09;% k 1 &#xff08;Ak 1 Ak&#xff09;% k 1 只要发现了同余数的情况就说明有一个区间满足了题目的要求。 这个方法的精妙之处就在于前缀和包括了…

STM32H7使用FileX库BUG,SD卡挂载失败

问题描述&#xff1a; 使用STM32H7ThreadXFileX&#xff0c;之前使用swissbit牌的存储卡可正常使用&#xff0c;最近项目用了金士顿的存储卡&#xff0c;发现无法挂载文件系统。 原因分析&#xff1a; 调试过程发现&#xff0c;关闭D-Cache可以挂载使用exfat文件系统。 File…

C语言-用二分法在一个有序数组中查找某个数字

1.题目描述 有15个数按由大到小顺序放在一个数组中&#xff0c;输入一个数&#xff0c;要求用折半查找法找出该数是数组中第几个元素的值。如果该数不在数组中&#xff0c;则输出“无此数” 二.思路分析 记录数组中左边第一个元素的下标为left&#xff0c;记录数组右边第一个…

2024年畜牧、养殖业与智慧农业国际会议(ICLAHSA2024)

2024年畜牧、养殖业与智慧农业国际会议(ICLAHSA2024) 会议简介 2024国际畜牧业与智慧农业大会&#xff08;ICLAHSA2024&#xff09;将在深圳隆重举行。本次大会旨在汇聚全球畜牧业、畜牧业、智慧农业等领域的专家学者&#xff0c;共同探索行业前沿技术、创新模式和发展趋势…

电脑回收站的东西还原后会在哪里?一文给你答案!

“很奇怪&#xff0c;想问问大家&#xff0c;我电脑回收站里还原的文件会被保存在哪里呀&#xff1f;刚刚恢复文件的时候本来想直接将它拖出&#xff0c;却发现文件不见了&#xff0c;这种情况应该怎么解决呢&#xff1f;” 电脑回收站是一个特殊的文件夹&#xff0c;用于临时存…

【LLMOps】小白详细教程,在Dify中创建并使用自定义工具

文章目录 博客详细讲解视频点击查看高清脑图 1. 搭建天气查询http服务1.1. flask代码1.2. 接口优化方法 2. 生成openapi json schema2.1. 测试接口2.2. 生成openapi schema 3. 在dify中创建自定义工具3.1. 导入schema3.2. 设置工具认证信息3.3. 测试工具 4. 调用工具4.1. Agent…

PC-3000 Mobile Pro: 智能手机及平板设备数据提取工具

天津鸿萌科贸发展有限公司从事数据安全业务20余年&#xff0c;在数据恢复、数据取证、数据备份等领域有丰富的案例经验、前沿专业技术及良好的行业口碑。同时&#xff0c;公司面向取证机构及数据恢复公司&#xff0c;提供数据恢复实验室建设方案&#xff0c;包含数据恢复硬件设…

跨境电商亚马逊、虾皮等平台做测评要用什么IP?

IP即IP地址&#xff0c;IP地址是指互联网协议地址&#xff08;英语&#xff1a;Internet Protocol Address&#xff0c;又译为网际协议地址&#xff09;&#xff0c;是IP Address的缩写&#xff0c;IP地址是IP协议提供的一种统一的地址格式 功能&#xff1a;它为互联网上的每一…

SpringMVC笔记——SpringMVC基础Tomcat环境配置

Tomcat安装配置 下载Apache Tomcat 进入官网https://tomcat.apache.org/&#xff0c;选择tomcat 9 这边使用idea开发&#xff0c;建议直接下载压缩包 无法访问下载的可以直接用我的下载链接&#xff1a;https://cloudreve.zxbdwy.online/s/6nSA 提取码&#xff1a;w1pwk3将压…

嵌入式学习60-C++

知识零碎&#xff1a; C# &#xff1a;window下用于vs stdio编程 …

Pyside6:QDialog按钮变为中文

如果在Qt Designer中创建了一个Qdialog&#xff0c;自带按钮的类型&#xff0c;那么在Designer中显示是中文&#xff0c;但在运行时将变成英文。 如果程序不需要进行国际化&#xff0c;只在国内使用&#xff0c;那么进行中文化的操作还是有必要的&#xff0c;其实方式很简单&am…