当前位置: 首页 > news >正文

【Rust结构体】Rust结构体详解:从基础到高级应用

在这里插入图片描述

✨✨ 欢迎大家来到景天科技苑✨✨

🎈🎈 养成好习惯,先赞后看哦~🎈🎈

🏆 作者简介:景天科技苑
🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。
🏆《博客》:Rust开发,Python全栈,Golang开发,云原生开发,PyQt5和Tkinter桌面开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi,flask等框架,云原生K8S,linux,shell脚本等实操经验,网站搭建,数据库等分享。

所属的专栏:Rust语言通关之路
景天的主页:景天科技苑

在这里插入图片描述

文章目录

  • Rust结构体
    • 1. 结构体基础
      • 1.1 什么是结构体
      • 1.2 定义和实例化结构体
      • 1.3 访问结构体字段
      • 1.4 可变结构体
      • 1.5 字段初始化简写
      • 1.6 结构体更新语法
    • 2. 结构体高级特性
      • 2.1 元组结构体
      • 2.2 类单元结构体
      • 2.3 结构体所有权
      • 2.4 打印结构体
      • 2.5 结构体方法语法
      • 2.6 多个impl块
      • 2.7 关联函数
      • 2.8 关联变量
    • 3. 实际应用案例
      • 3.1 图形计算
      • 3.2 学生管理系统
      • 3.3 银行账户系统
    • 4. 最佳实践和常见模式
      • 4.1 构建者模式
      • 4.2 使用Newtype模式
      • 4.3 结构体解构
    • 5. 性能考虑
      • 5.1 结构体布局
      • 5.2 零成本抽象
      • 5.3 内联优化
    • 6. 总结

Rust结构体

1. 结构体基础

1.1 什么是结构体

结构体(struct)是Rust中一种自定义数据类型,它允许你将多个相关的值组合在一起,形成一个有意义的组。结构体是创建更复杂数据类型的基础,也是面向对象编程中"对象"概念的基石。

与元组类似,结构体的每个部分可以是不同类型。但与元组不同,结构体需要为每个部分命名,这使得数据访问更加清晰明确。

1.2 定义和实例化结构体

定义结构体使用struct关键字,后跟结构体名称和大括号内的字段定义:
结构体与元组类似。就像元组,结构体的每一部分可以是不同类型。
不同于元组,结构体需要命名各部分数据以便能清楚的表明其值的意义。
由于有了这些名字使得结构体比元组更灵活:不需要依赖顺序来指定或访问实例中的值。
定义结构体,需要使用 struct 关键字并为整个结构体提供一个名字。结构体的名字需要描述它所组合的数据的意义。
接着,在大括号中,定义每一部分数据的名字,它们被称作 字段(field)或属性,并定义字段类型。
结构体名首字母一般大写

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

实例化结构体:
一旦定义了结构体后,为了使用它,通过为每个字段指定具体值来创建这个结构体的 实例。
创建一个实例需要以结构体的名字开头,接着在大括号中使用 key: value 对的形式提供字段,其中 key 是字段的名字,value 是需要储存在字段中的数据值。
实例中具体说明字段的顺序不需要和它们在结构体中声明的顺序一致。换句话说,结构体的定义就像一个类
型的通用模板,而实例则会在这个模板中放入特定数据来创建这个类型的值。

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

1.3 访问结构体字段

使用点号.访问结构体字段:
为了从结构体中获取某个特定的值,可以使用点号(.)来获取结构体中的属性。如果我们只想要用户的邮箱地址,可以用 user1.email 。
要更改结构体中的值,如果结构体的实例是可变的,我们可以使用点号并为对应的字段赋值。
故要修改结构体的值,必须在创建结构体实例的时候,将实例设为mut 可变结构体,才能修改。
注意整个实例必须是可变的;Rust 并不允许只将特定字段标记为可变。另外需要注意同其他任何表达式一样,我们可以
在函数体的最后一个表达式构造一个结构体,从函数隐式的返回一个结构体的新实例。

println!("User email: {}", user1.email);

1.4 可变结构体

如果要修改结构体字段,整个结构体实例必须是可变的:

let mut user1 = User {// ...
};user1.email = String::from("newemail@example.com");

Rust不允许只将某些字段标记为可变 - 要么整个实例可变,要么都不可变。

1.5 字段初始化简写

当变量名与字段名相同时,可以使用字段初始化简写语法:

fn build_user(email: String, username: String) -> User {User {email,    // 等同于 email: emailusername, // 等同于 username: usernameactive: true,sign_in_count: 1,}
}

1.6 结构体更新语法

可以从老的对象创建新的对象常常是很有帮助的,即复用大部分老对象的值并只改变一部分值。
可以使用其他实例创建新实例:

 //创建结构体实例let mut user1 = User{username: String::from("jingtian"),email: String::from("jingtian@example.com"),count: String::from("1000010"),nonce: 100000,active: true,};let user3 = User{username: String::from("zhangsan"),email: String::from("zhangsan@example.com"),count: String::from("1000013"),nonce: 50,active: user1.active, //这里直接引用user1的字段来创建};//获取结构体的值println!("zhangsan username={},email={},count={},nonce={},active={}",user3.username,user3.email,user3.count,user3.nonce,user3.active);

能拿到值
在这里插入图片描述
如果是多个字段引用旧对象,还可以更简化
使用结构体更新语法,我们可以通过更少的代码来达到相同的效果。 … 语法指定了剩余未显式设置值的字段应有与给定实例对应字段相同的值。

let user3 = User{username: String::from("zhangsan"),email: String::from("zhangsan@example.com"),..user1 //.. 语法指定了剩余未显式设置值的字段应有与给定实例对应字段相同的值
};//获取结构体的值
println!("zhangsan username={},email={},count={},nonce={},active={}",user3.username,user3.email,user3.count,user3.nonce,user3.active);

使用结构体更新语法为一个 User 实例设置新的 email 和 username 值,不过其余值来自 user1 变量中实例的字段
在这里插入图片描述
注意:使用结构体语法更新,user1字段后面不能加逗号,the base struct must always be the last field
并且user1对象在使用语法更新后,属于被借用了,后面不能使用该对象了
否则会报错
在这里插入图片描述

2. 结构体高级特性

2.1 元组结构体

元组结构体(tuple struct)有名字但没有字段名,只有字段类型:
使用没有命名字段的元组结构体来创建不同的类型
也可以定义与元组类似的结构体,称为 元组结构体(tuple structs),有着结构体名称提供的含义,但没有具体的字段名,只有字段的类型。
元组结构体在你希望命名整个元组并使其与其他(同样的)元组为不同类型时很有用,这时像常规结构体那样为每个字段命名就显得冗余和形式化了。
定义元组结构体以 struct 关键字和结构体名开头并后跟元组中的类型。
例如,这里是两个分别叫做 Color 和 Point 元组结构体的定义和用例:

//元组结构体
struct Color(i32, i32, i32);
struct Point(i32, i32, i32);
let black = Color(255, 110, 220);
let origin = Point(112, 213, 290);
println!("black0={}",black.0);  //通过下标来获取元组的值
println!("black1={}",black.1);
println!("black2={}",black.2);

在这里插入图片描述

元组结构体适用于需要给元组命名并使其不同于其他同类型元组的场景。

2.2 类单元结构体

没有任何字段的结构体称为类单元结构体(unit-like struct):

struct AlwaysEqual;let subject = AlwaysEqual;

这种结构体常用于需要在某个类型上实现trait但不需要存储数据的情况。

2.3 结构体所有权

前面的User结构体使用了String而不是&str字符串切片,这意味着结构体拥有其数据的所有权。如果要使用引用,需要使用生命周期:

struct User {username: &str,  // 错误:需要生命周期说明符email: &str,sign_in_count: u64,active: bool,
}

正确的带生命周期的定义:

struct User<'a> {username: &'a str,email: &'a str,sign_in_count: u64,active: bool,
}

2.4 打印结构体

上面我们打印结构体,都是打印结构体中的某些字段,非常不方便。
有没有更快捷打印出结构体的方法呢?
可以采用自动推导的方法
只需要在定义结构体的时候,上方加上 #[derive(Debug)]

要实现Debug trait来打印结构体:

#[derive(Debug)]
struct Rectangle {width: u32,height: u32,
}let rect = Rectangle { width: 30, height: 50 };
println!("rect is {:?}", rect);  // 单行打印
println!("rect is {:#?}", rect); // 美化多行打印

2.5 结构体方法语法

方法 与函数类似:它们使用 fn 关键字和名称声明,可以拥有参数和返回值,同时包含一段该方法在某处被调用时会执行的代码。
不过方法与函数是不同的,因为它们在结构体的上下文中被定义(或者是枚举或 trait 对象的上下文),并且它们第一个参数总是 &self ,它代表调用该方法的结构体实例。

定义结构体的方法,使用impl关键字, impl 是 implementation 的缩写,后面跟实现哪个结构体,就是哪个结构体的方法
fn定义的函数放到impl 大括号中,函数的第一个参数必须是 &self 。

impl Rectangle {fn area(&self) -> u32 {self.width * self.height}fn can_hold(&self, other: &Rectangle) -> bool {self.width > other.width && self.height > other.height}// 关联函数(静态方法)fn square(size: u32) -> Rectangle {Rectangle { width: size, height: size }}
}

使用方法:

let rect1 = Rectangle { width: 30, height: 50 };
println!("Area: {}", rect1.area());let rect2 = Rectangle { width: 10, height: 40 };
println!("Can rect1 hold rect2? {}", rect1.can_hold(&rect2));let square = Rectangle::square(10);  // 调用关联函数

2.6 多个impl块

可以为同一个结构体定义多个impl块:

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

2.7 关联函数

impl 块的另一个有用的功能是:允许在 impl 块中定义 不 以 self 作为参数的函数。
这被称为 关联函数(associatedfunctions),因为它们与结构体相关联。
即便如此它们仍是函数而不是方法,因为它们并不作用于一个结构体的实例。
我们已经使用过 String::from 关联函数了。
关联函数经常被用作返回一个结构体新实例的构造函数。

使用结构体名和 ::函数名() 语法来调用这个关联函数:比如 let sq = Rectangle::square(3); 。
这个方法位于结构体的命名空间中: :: 语法用于关联函数和模块创建的命名空间

//创建结构体
struct Dog {name: String,age: u8,
}impl Dog {//创建方法fn bark(&self) {println!("Woof! My name is {} and I am {} years old.", self.name, self.age);}//关联函数,返回结构体Dog,也可以用Self 替代fn new(name: String, age: u8) -> Dog {Dog { name, age }}//关联变量const PI: f64 = 3.14;//静态方法fn static_method() {println!("This is a static method.");}
}fn main() {//调用关联变量println!("PI: {}", Dog::PI);//调用静态方法Dog::static_method();//实例化结构体 可以通过调用关联函数来实例化,调用关联函数,结构体名::函数名()let dog = Dog::new(String::from("Buddy"), 3);//调用方法dog.bark();}

在这里插入图片描述

2.8 关联变量

这里的关联边变量指的是,和结构体类型相关的变量,也可以在特质或者枚举中

impl Dog {const PI: f64 = 3.14}

调用时使用 Dog::PI
在这里插入图片描述

3. 实际应用案例

3.1 图形计算

#[derive(Debug)]
struct Point {x: f64,y: f64,
}impl Point {fn new(x: f64, y: f64) -> Point {Point { x, y }}fn distance(&self, other: &Point) -> f64 {((self.x - other.x).powi(2) + (self.y - other.y).powi(2)).sqrt()}
}#[derive(Debug)]
struct Triangle {a: Point,b: Point,c: Point,
}impl Triangle {fn perimeter(&self) -> f64 {self.a.distance(&self.b) + self.b.distance(&self.c) + self.c.distance(&self.a)}fn area(&self) -> f64 {let ab = self.a.distance(&self.b);let bc = self.b.distance(&self.c);let ca = self.c.distance(&self.a);let s = self.perimeter() / 2.0;(s * (s - ab) * (s - bc) * (s - ca)).sqrt()}
}fn main() {let a = Point::new(0.0, 0.0);let b = Point::new(3.0, 0.0);let c = Point::new(0.0, 4.0);let triangle = Triangle { a, b, c };println!("Triangle perimeter: {}", triangle.perimeter());println!("Triangle area: {}", triangle.area());
}

3.2 学生管理系统

#[derive(Debug)]
struct Student {id: u32,name: String,age: u8,courses: Vec<Course>,
}#[derive(Debug)]
struct Course {name: String,credit: u8,score: Option<u8>, // 使用Option表示可能没有成绩
}impl Student {fn new(id: u32, name: String, age: u8) -> Student {Student {id,name,age,courses: Vec::new(),}}fn add_course(&mut self, name: String, credit: u8) {self.courses.push(Course {name,credit,score: None,});}fn update_score(&mut self, course_name: &str, score: u8) -> Result<(), String> {for course in &mut self.courses {if course.name == course_name {course.score = Some(score);return Ok(());}}Err(format!("Course {} not found", course_name))}fn calculate_gpa(&self) -> Option<f64> {if self.courses.is_empty() {return None;}let (total_score, total_credit) = self.courses.iter().filter_map(|c| c.score.map(|s| (s as f64 * c.credit as f64, c.credit as f64))).fold((0.0, 0.0), |(sum_score, sum_credit), (score, credit)| {(sum_score + score, sum_credit + credit)});Some(total_score / total_credit)}
}fn main() {let mut student = Student::new(1, String::from("Alice"), 20);student.add_course(String::from("Math"), 4);student.add_course(String::from("Physics"), 3);student.add_course(String::from("Chemistry"), 3);student.update_score("Math", 90).unwrap();student.update_score("Physics", 85).unwrap();student.update_score("Chemistry", 78).unwrap();println!("Student: {:?}", student);println!("GPA: {:.2}", student.calculate_gpa().unwrap());
}

3.3 银行账户系统

use std::fmt;#[derive(Debug)]
struct BankAccount {account_number: String,holder_name: String,balance: f64,transactions: Vec<Transaction>,
}#[derive(Debug)]
enum TransactionType {Deposit,Withdrawal,Transfer,
}#[derive(Debug)]
struct Transaction {transaction_type: TransactionType,amount: f64,description: String,timestamp: String, // 简化处理,实际应用中应使用专门的日期时间类型
}impl BankAccount {fn new(account_number: String, holder_name: String) -> BankAccount {BankAccount {account_number,holder_name,balance: 0.0,transactions: Vec::new(),}}fn deposit(&mut self, amount: f64, description: String) -> Result<(), String> {if amount <= 0.0 {return Err("Deposit amount must be positive".to_string());}self.balance += amount;self.add_transaction(TransactionType::Deposit, amount, description);Ok(())}fn withdraw(&mut self, amount: f64, description: String) -> Result<(), String> {if amount <= 0.0 {return Err("Withdrawal amount must be positive".to_string());}if self.balance < amount {return Err("Insufficient funds".to_string());}self.balance -= amount;self.add_transaction(TransactionType::Withdrawal, amount, description);Ok(())}fn transfer(&mut self, to_account: &mut BankAccount, amount: f64, description: String) -> Result<(), String> {if amount <= 0.0 {return Err("Transfer amount must be positive".to_string());}if self.balance < amount {return Err("Insufficient funds for transfer".to_string());}self.balance -= amount;to_account.balance += amount;let desc_self = format!("Transfer to {}: {}", to_account.account_number, description);let desc_to = format!("Transfer from {}: {}", self.account_number, description);self.add_transaction(TransactionType::Transfer, amount, desc_self);to_account.add_transaction(TransactionType::Transfer, amount, desc_to);Ok(())}fn add_transaction(&mut self, transaction_type: TransactionType, amount: f64, description: String) {// 简化时间戳处理let timestamp = "2023-01-01 12:00:00".to_string();self.transactions.push(Transaction {transaction_type,amount,description,timestamp,});}fn print_statement(&self) {println!("Account Statement for {}", self.account_number);println!("Holder: {}", self.holder_name);println!("Current Balance: {:.2}", self.balance);println!("\nTransactions:");println!("{:<20} {:<10} {:<15} {}", "Date", "Type", "Amount", "Description");for txn in &self.transactions {println!("{:<20} {:<10} {:<15.2} {}", txn.timestamp,match txn.transaction_type {TransactionType::Deposit => "DEPOSIT",TransactionType::Withdrawal => "WITHDRAW",TransactionType::Transfer => "TRANSFER",},txn.amount,txn.description);}}
}impl fmt::Display for BankAccount {fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {write!(f, "Account {} ({}): Balance {:.2}", self.account_number, self.holder_name, self.balance)}
}fn main() {let mut account1 = BankAccount::new("123456".to_string(), "Alice".to_string());let mut account2 = BankAccount::new("654321".to_string(), "Bob".to_string());account1.deposit(1000.0, "Initial deposit".to_string()).unwrap();account1.withdraw(200.0, "Cash withdrawal".to_string()).unwrap();account1.transfer(&mut account2, 300.0, "Rent payment".to_string()).unwrap();println!("{}", account1);println!("{}", account2);account1.print_statement();
}

4. 最佳实践和常见模式

4.1 构建者模式

Rust没有默认参数和重载,构建者模式是创建复杂结构体的常用方式:

struct Computer {cpu: String,memory: u32,storage: u32,gpu: Option<String>,has_wifi: bool,has_bluetooth: bool,
}struct ComputerBuilder {cpu: String,memory: u32,storage: u32,gpu: Option<String>,has_wifi: bool,has_bluetooth: bool,
}impl ComputerBuilder {fn new(cpu: String, memory: u32, storage: u32) -> ComputerBuilder {ComputerBuilder {cpu,memory,storage,gpu: None,has_wifi: false,has_bluetooth: false,}}fn gpu(mut self, gpu: String) -> ComputerBuilder {self.gpu = Some(gpu);self}fn wifi(mut self, has_wifi: bool) -> ComputerBuilder {self.has_wifi = has_wifi;self}fn bluetooth(mut self, has_bluetooth: bool) -> ComputerBuilder {self.has_bluetooth = has_bluetooth;self}fn build(self) -> Computer {Computer {cpu: self.cpu,memory: self.memory,storage: self.storage,gpu: self.gpu,has_wifi: self.has_wifi,has_bluetooth: self.has_bluetooth,}}
}impl Computer {fn print_specs(&self) {println!("CPU: {}", self.cpu);println!("Memory: {} GB", self.memory);println!("Storage: {} GB", self.storage);if let Some(gpu) = &self.gpu {println!("GPU: {}", gpu);} else {println!("GPU: Integrated");}println!("Wi-Fi: {}", if self.has_wifi { "Yes" } else { "No" });println!("Bluetooth: {}", if self.has_bluetooth { "Yes" } else { "No" });}
}fn main() {let gaming_pc = ComputerBuilder::new("Intel i7".to_string(), 16, 1000).gpu("NVIDIA RTX 3080".to_string()).wifi(true).bluetooth(true).build();gaming_pc.print_specs();let office_pc = ComputerBuilder::new("Intel i5".to_string(), 8, 500).wifi(true).build();office_pc.print_specs();
}

4.2 使用Newtype模式

Newtype模式是在现有类型上创建新类型的一种方式,用于增加类型安全和表达意图:

struct Email(String);impl Email {fn new(email: &str) -> Result<Email, String> {if email.contains('@') {Ok(Email(email.to_string()))} else {Err("Invalid email format".to_string())}}
}struct User {name: String,email: Email,
}fn send_email(email: &Email, message: &str) {println!("Sending '{}' to {}", message, email.0);
}fn main() {let email = Email::new("user@example.com").unwrap();let user = User {name: "Alice".to_string(),email,};send_email(&user.email, "Hello from Rust!");// 下面的代码会编译错误,因为类型不匹配// let invalid_email = "not-an-email".to_string();// send_email(&invalid_email, "This won't work");
}

4.3 结构体解构

可以使用模式匹配来解构结构体:

struct Point3D {x: i32,y: i32,z: i32,
}fn print_coordinates(&Point3D { x, y, z }: &Point3D) {println!("x: {}, y: {}, z: {}", x, y, z);
}fn main() {let point = Point3D { x: 1, y: 2, z: 3 };print_coordinates(&point);// 也可以在let语句中解构let Point3D { x, y, z } = point;println!("x is {}", x);// 可以忽略某些字段let Point3D { x, .. } = Point3D { x: 4, y: 5, z: 6 };println!("only x: {}", x);
}

5. 性能考虑

5.1 结构体布局

Rust默认会对结构体字段进行重排以优化内存使用:

struct Unoptimized {a: u8,   // 1字节b: u32,  // 4字节c: u16,  // 2字节
}struct Optimized {b: u32,  // 4字节c: u16,  // 2字节a: u8,   // 1字节
}fn main() {println!("Unoptimized size: {}", std::mem::size_of::<Unoptimized>()); // 可能输出12println!("Optimized size: {}", std::mem::size_of::<Optimized>());     // 可能输出8
}

可以使用#[repr(C)]属性禁用这种优化,保持C兼容的布局:

#[repr(C)]
struct CLike {a: u8,b: u32,c: u16,
}

5.2 零成本抽象

Rust的结构体和方法是零成本抽象,编译后的代码与直接操作数据一样高效:

#[derive(Debug)]
struct Vector3D {x: f64,y: f64,z: f64,
}impl Vector3D {fn dot(&self, other: &Vector3D) -> f64 {self.x * other.x + self.y * other.y + self.z * other.z}fn cross(&self, other: &Vector3D) -> Vector3D {Vector3D {x: self.y * other.z - self.z * other.y,y: self.z * other.x - self.x * other.z,z: self.x * other.y - self.y * other.x,}}
}fn main() {let v1 = Vector3D { x: 1.0, y: 2.0, z: 3.0 };let v2 = Vector3D { x: 4.0, y: 5.0, z: 6.0 };println!("Dot product: {}", v1.dot(&v2));println!("Cross product: {:?}", v1.cross(&v2));
}

5.3 内联优化

小结构体通常会被编译器内联,消除方法调用的开销:

#[derive(Clone, Copy)]
struct Point2D {x: f32,y: f32,
}impl Point2D {#[inline]fn distance_squared(&self, other: Point2D) -> f32 {let dx = self.x - other.x;let dy = self.y - other.y;dx * dx + dy * dy}fn distance(&self, other: Point2D) -> f32 {self.distance_squared(other).sqrt()}
}

6. 总结

Rust的结构体是构建复杂数据类型的基础,提供了强大的数据组织和抽象能力。通过本文,我们学习了:

  1. 结构体的基本定义和实例化
  2. 方法语法和关联函数
  3. 高级特性如元组结构体和类单元结构体
  4. 实际应用案例:图形计算、学生管理、银行账户
  5. 设计模式如构建者模式和Newtype模式
  6. 性能考虑和优化技巧

结构体与Rust的其他特性如trait、泛型、生命周期等结合,可以构建出既安全又高效的复杂系统。掌握结构体的使用是成为Rust熟练开发者的重要一步。

相关文章:

【Rust结构体】Rust结构体详解:从基础到高级应用

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…...

Java面试实战:音视频场景下的微服务架构与缓存技术剖析

面试场景描述 谢飞机&#xff0c;一位自称“全栈工程师”的程序员&#xff0c;来到一家互联网大厂参加Java开发岗位的面试。面试官是一位严肃的技术专家&#xff0c;他希望通过一系列问题考察谢飞机的实际技术水平。 第一轮提问&#xff08;基础问题&#xff09; 面试官&…...

Vue 3 的核心组合式 API 函数及其完整示例、使用场景和总结表格

以下是 Vue 3 的核心组合式 API 函数及其完整示例、使用场景和总结表格&#xff1a; 1. ref 作用 创建一个响应式引用值&#xff0c;用于管理基本类型或单个值的响应式状态。 示例 <template><div><p>Count: {{ count }}</p><button click&quo…...

Kotlin学习基础知识大全(上)

文章目录 Kotlin基础知识全面解析第一章&#xff1a;Kotlin语言概述1.1 Kotlin的发展历程1.2 Kotlin的设计目标1.3 Kotlin的应用领域1.4 Kotlin与Java的比较 第二章&#xff1a;Kotlin基础语法2.1 变量与常量2.2 基本数据类型数字类型示例&#xff1a;字符和字符串示例&#xf…...

【Java面试笔记:进阶】18.什么情况下Java程序会产生死锁?如何定位、修复?

死锁(Deadlock)是指两个或多个线程因竞争资源而无限期阻塞的现象。 1. 死锁的定义与产生原因 定义:死锁是一种程序状态,多个线程或进程因循环依赖而永久处于等待状态,无法继续执行。 根据 Coffman 条件,死锁产生需同时满足以下四个必要条件: 互斥(Mutual Exclusion)…...

PS Mac Photoshop 2025 for Mac图像处理 PS 2025安装笔记

Mac分享吧 文章目录 效果一、准备工作二、开始安装1、Anticc简化版安装1.1双击运行软件&#xff0c;安装1.2 解决来源身份不明的开发者问题**此代码为打开&#xff1a;系统偏好设置 – 隐私与安全性&#xff0c;中的【任何来源】&#xff0c;如下图&#xff1a;**1.3 再次运行…...

HarmonyOS 框架基础知识

参考文档&#xff1a;HarmonyOS开发者文档 第三方库&#xff1a;OpenHarmony三方库中心仓 基础特性 Entry&#xff1a;关键装饰器 Components&#xff1a;组件 特性EntryComponent​​作用范围仅用于页面入口可定义任意可复用组件​​数量限制​​每个页面有且仅有一个无数量…...

LabVIEW实现Voronoi图绘制功能

该 LabVIEW 虚拟仪器&#xff08;VI&#xff09;借助 MathScript 节点&#xff0c;实现基于手机信号塔位置计算 Voronoi 图的功能。通过操作演示&#xff0c;能直观展示 Voronoi 图在空间划分上的应用。 各部分功能详细说明 随机地形创建部分 功能&#xff1a;根据 “Maximum a…...

centos7的环境下ollama 如何卸载

在 CentOS 7 环境下卸载 ollama&#xff0c;可以按照以下步骤操作。假设 ollama 是通过手动安装的&#xff0c;以下是卸载的详细步骤。 1. 停止所有运行中的 ollama 进程 在卸载之前&#xff0c;确保所有与 ollama 相关的进程都已停止。 查找并停止进程 ps aux | grep ollam…...

中心极限定理(CLT)习题集 · 答案与解析篇

中心极限定理(CLT)习题集 答案与解析篇 与题目篇一一对应。若有其他解法欢迎在评论区补充。 1. 概念与判断题 1.1 经典叙述 若 (X_1,X_2,\dots) i.i.d.,满足 (E[X_1]=\mu,;0<\sigma^2:=\operatorname{Var}(X_1)<\infty)。 则 [ Z_n=\frac{\sum_{k=1}^{n}(X_k-\mu)}…...

Spring Cloud Gateway配置双向SSL认证(完整指南)

本文将详细介绍如何为Spring Cloud Gateway配置双向SSL认证,包括证书生成、配置和使用。 目录结构 /my-gateway-project ├── /certs │ ├── ca.crt # 根证书 │ ├── ca.key # 根私钥 │ ├── gateway.crt # 网关证书 │ ├── …...

中间系统-SPF计算

SPF计算 isis如何计算路由&#xff1a;以自己为根构建SPF树&#xff0c;之后填充叶子。 <R1>display isis lsdb 0000.0000.0001.00-00 verbose //查看lsp的详细信息 SOURCE 0000.0000.0001.00 //源节点系统&#xff0c;用于标识产生该LSP的路由器…...

立马耀:通过阿里云 Serverless Spark 和 Milvus 构建高效向量检索系统,驱动个性化推荐业务

作者&#xff1a;厦门立马耀网络科技有限公司大数据开发工程师 陈宏毅 背景介绍 行业 蝉选是蝉妈妈出品的达人选品服务平台。蝉选秉持“陪伴达人赚到钱”的品牌使命&#xff0c;致力于洞悉达人变现需求和痛点&#xff0c;提供达人选高佣、稳变现、速响应的选品服务。 业务特…...

Diffusion inversion后的latent code与标准的高斯随机噪音不一样

可视化latents_list如下; 可视化最后一步与标准的噪声&#xff1a; 能隐约看出到最后一步还是会有“马”的形状 整个代码&#xff08;及可视化代码如下&#xff09;&#xff1a; ## 参考freeprompt(FPE)的代码 import os import torch import torch.nn as nn import torch.n…...

C语言-函数-1

以下是我初学C语言的笔记记录&#xff0c;欢迎在评论区留言补充 一&#xff0c;函数分为几类 * 函数分为两类&#xff1a; 一类是库函数&#xff1b;一类是自定义函数 * 库函数&#xff1a; 系统自己带的&#xff0c;在使用时候&#xff0c;要用到头文件&#xff1b; 查询库函…...

AXOP34032: 40V/40µA 轨到轨输入输出双通道运算放大器

AXOP34032是一款通用型高压低功耗双通道运算放大器&#xff0c;产品的工作电压为2.5V至40V&#xff0c;具有1.2MHz的带宽&#xff0c;压摆率为 0.7V/μs&#xff0c;单路静态电流为40A。该产品非常适合需要较高耐压的低功耗应用。 产品可选关断功能(AXOP34032S)。 主要特性 2…...

HTML5 服务器发送事件 (Server-Sent Events):实现网页自动获取服务器更新

一、引言 在现代 Web 应用开发中,实时性和动态交互性变得越来越重要。HTML5 引入的服务器发送事件(Server-Sent Events,简称 SSE)为网页获取来自服务器的实时更新提供了一种简单而有效的解决方案。与传统方式中网页需主动询问服务器是否有更新不同,SSE 能够让更新自动推送…...

如何创建和使用 Hive 视图

一、Hive 视图的基本概念 Hive 视图是一种虚拟表,其内容由查询语句定义,本身不存储实际数据。当查询视图时,Hive 会动态执行视图定义中的查询逻辑并返回结果。视图的核心作用是简化复杂查询、提供数据抽象和实现权限控制。例如,通过视图可以隐藏底层表的复杂关联关系,或限…...

快速体验tftp文件传输(嵌入式设备)

一、参考资料 Linux tftp 命令 | 菜鸟教程 Ubuntu最新版本(Ubuntu22.04LTS)安装Tftp服务及其使用教程-CSDN博客 Windows下的Tftpd32(Tftpd64)软件下载和使用教程-集成了Tftp服务器、客户端-CSDN博客 tftpd32 tftpd64文件传输安装和使用教程【图文并茂】-CSDN博客 二、快速…...

数据库进阶之MySQL 程序

1.目标 1> 了解mysqlId服务端程序 2> 掌握mysql客户端程序的使用 3> 了解工具包中的其他程序 2. MySQL程序简介 本章介绍 MySQL 命令⾏程序以及在运⾏这些程序时指定选项的⼀般语法(如:mysql -uroot -p)。 对常⽤程序进⾏详细的讲解(实用工具的使用方法)&#xf…...

细说STM32单片机FreeRTOS信号量和互斥量及二值信号量的应用实例

目录 一、信号量和互斥量概述 1、二值信号量 2、计数信号量 3、互斥量 4、递归互斥量 5、相关函数概述 &#xff08;1&#xff09; 负责创建的函数 &#xff08;2&#xff09; 负责释放和获取的函数 &#xff08;3&#xff09;负责返回数据的函数 二、二值信号量使用…...

云原生之认识DDD

一、DDD是什么? 领域驱动设计(DDD) 做为一种软件工程的方法论,它可以帮助我们设计高质量的软件,或者说任何工程的设计都需要方法论,不论是城市设计、建筑设计、室内设计。 比如没有方法论的情况下楼是可以盖起来的,或许整个楼道和窗户上挂满了电话线、闭路线、电线?下水…...

Kingbase 数据库物理备份与恢复操作手册

版本环境&#xff1a;KingbaseES V8R6 适用对象&#xff1a;DBA / 运维工程师 / 技术支持人员 目标用途&#xff1a;生产环境灾备保障、全量迁移、异地容灾恢复 一、物理备份操作流程 物理备份是指直接对数据库实例的物理文件进行复制&#xff0c;具备完整性强、恢复速度快等特…...

高等数学同步测试卷 同济7版 试卷部分 上 做题记录 第四章 不定积分同步测试卷 A卷

第四章 不定积分同步测试卷 A卷 一、单项选择题(本大题共5小题&#xff0c;每小题3分&#xff0c;总计15分) 1. 2. 3. 4. 5. 二、填空题(本大题共5小题,每小题3分,总计15 分) 6. 7. 8. 9. 10. 三、求解下列各题(本大题共5小题,每小题6分,总计30…...

【刷题Day25】用户态和内核态、Reactor、虚拟内存(浅)

什么是用户态和内核态&#xff1f; 用户态&#xff08;User Mode&#xff09;和内核态&#xff08;Kernel Mode&#xff09;是操作系统中的两种运行模式&#xff0c;用于区分应用程序与操作系统内核的操作权限。 两者区别在于权限级别&#xff1a; 用户态&#xff1a;应用程…...

使用Qt Quick Controls创建自定义日历组件

目录 引言相关阅读1. DayOfWeekRow2. MonthGrid3. WeekNumberColumn 项目结构及实现工程结构图代码实现及解析1. 组件封装2. 主界面实现 运行效果 总结下载链接 引言 Qt6 Quick框架提供了一套丰富的日历相关组件&#xff0c;包括 MonthGrid、DayOfWeekRow 和 WeekNumberColumn…...

Java 富文本转word

前言&#xff1a; 本文的目的是将传入的富文本内容(html标签&#xff0c;图片)并且分页导出为word文档。 所使用的为docx4j 一、依赖导入 <!-- 富文本转word --><dependency><groupId>org.docx4j</groupId><artifactId>docx4j</artifactId&…...

基于 Spring Boot 瑞吉外卖系统开发(七)

基于 Spring Boot 瑞吉外卖系统开发&#xff08;七&#xff09; 新增菜品页面 菜品管理页面提供了一个“新增菜品”按钮&#xff0c;单击该按钮时&#xff0c;会打开新增菜品页面。 菜品分类列表 首先要获取分类列表数据。 请求路径/category/list&#xff0c;请求方法GE…...

react 子组件暴露,父组件接收

// Child.jsx import React, { forwardRef, useImperativeHandle, useState } from react; import { Form, Input } from antd;const Child forwardRef((props, ref) > {const [form] Form.useForm();const [customState, setCustomState] useState(默认值);useImperativ…...

如何在Spring Boot中配置自定义端口运行应用程序

Spring Boot 应用程序默认在端口 8080 上运行嵌入式 Web 服务器&#xff08;如 Tomcat、Jetty 或 Undertow&#xff09;。然而&#xff0c;在开发、测试或生产环境中&#xff0c;开发者可能需要将应用程序配置为在自定义端口上运行&#xff0c;例如避免端口冲突、适配微服务架构…...

5.第五章:数据分类的方法论

文章目录 5.1 传统分类方法5.1.1 基于规则的分类方法5.1.2 基于统计的分类方法5.1.3 传统分类方法的局限性 5.2 现代分类技术5.2.1 神经网络分类模型5.2.2 深度学习分类方法5.2.3 现代分类技术的优势 5.3 创新分类方法5.3.1 小样本学习方法5.3.2 零样本学习方法5.3.3 主动学习方…...

如何在 Unity 中导入 gltf /glb 文件

遗憾的是&#xff0c;默认情况下&#xff0c;Unity 无法导入 gltf 文件。 我们有 个好消息要告诉你 gltf&#xff0c;有一种方法可以将 glb 文件格式导入 Unity&#xff01; 看完这篇文章后&#xff0c;让我们将 “gltf&#xff0c; glb” 文件放入 Unity 中&#xff0c;并将其…...

Docker部署一款开源的极简服务器监控工具Ward内网穿透远程使用

文章目录 前言1.关于Ward2.Docker部署3.简单使用ward4.安装cpolar内网穿透5. 配置ward公网地址6. 配置固定公网地址总结 前言 各位小伙伴们&#xff0c;你们是不是也遇到过这样的情况&#xff1a;每次打开服务器管理界面&#xff0c;密密麻麻的数据和图表看得你眼花缭乱&#…...

Day11(回溯法)——LeetCode79.单词搜索

1 前言 今天主要刷了一道热题榜中回溯法的题&#xff0c;现在的计划是先刷热题榜专题吧&#xff0c;感觉还是这样见效比较快。因此本文主要介绍LeetCode79。 2 LeetCode79.单词搜索(LeetCode79) OK题目描述及相关示例如下&#xff1a; 2.1 题目分析解决及优化 感觉回溯的方…...

数据结构-图

一、图的定义与基本术语 图&#xff08;Graph&#xff09;是一种非线性数据结构&#xff0c;由顶点&#xff08;Vertex&#xff09;和边&#xff08;Edge&#xff09;组成。它包含以下基本术语&#xff1a; 顶点&#xff08;Vertex&#xff09; &#xff1a;是图中的数据元素。…...

数据结构-选择排序(Python)

目录 选择排序算法思想 选择排序算法步骤 选择排序代码实现 选择排序算法分析 选择排序算法思想 选择排序&#xff08;Selection Sort&#xff09;基本思想&#xff1a; 将数组分为两个区间&#xff1a;左侧为已排序区间&#xff0c;右侧为未排序区间。每趟从未排序区间中…...

[特殊字符] 分布式定时任务调度实战:XXL-JOB工作原理与路由策略详解

在微服务架构中&#xff0c;定时任务往往面临多实例重复执行、任务冲突等挑战。为了解决这一问题&#xff0c;企业级调度框架 XXL-JOB 提供了强大的任务统一调度与执行机制&#xff0c;特别适合在分布式系统中使用。 本文将从 XXL-JOB 的核心架构入手&#xff0c;详细讲解其调…...

【前端】基于 Promise 的 HTTP 客户端工具Axios 详解

Axios 详解 1. 简介 定义&#xff1a;Axios 是一个基于 Promise 的 HTTP 客户端&#xff0c;用于浏览器和 Node.js 环境&#xff0c;简化 HTTP 请求的发送和处理。核心特点&#xff1a; 支持 Promise API&#xff0c;可链式调用。自动转换 JSON 数据。支持请求/响应拦截。可取…...

React Native 安卓端 android Image 播放gif webp 动态图

React Native 安卓端 android Image 播放gif webp 动态图 RN项目是0.78.2 React是19.0 基本介绍 Image 是 React Native 中用于显示各种类型图片的核心组件&#xff0c;支持显示网络图片、静态资源、本地图片以及 base64 编码的图片。在 Android 端&#xff0c;Image 组件还可…...

【mysql】windows mysql命令

终端配置环境变量&#xff0c;找到mysql地址放入环境变量-系统变量中 例如&#xff1a; C:\Program Files\MySQL\MySQL Server 8.0\bin win键R输入 sysdm.cpl 快速打开电脑变量-高级-环境变量 连接命令 mysql -u root -p 查看所有数据库 show databases; 选中数据库 …...

uniappx 打包配置32位64位x86安装包

{"app": {"distribute": {"android": {"abiFilters": ["armeabi-v7a","arm64-v8a","x86","x86_64"]}}} }...

【C++ 类和数据抽象】static 类成员

目录 一、static 类成员的基本概念 1.1 静态成员的定义 1.2 静态数据成员 1.3 静态成员函数 1.4 内存布局 1.5 访问控制 1.6 性能分析 1.7 C标准演进 二、static 类成员的特点 2.1 共享性 2.2 不依赖于对象 2.3 无 this 指针 三、静态成员的初始化规则 3.1 初始化…...

深入了解递归、堆与栈:C#中的内存管理与函数调用

在编程中&#xff0c;理解如何有效地管理内存以及如何控制程序的执行流程是每个开发者必须掌握的基本概念。C#作为一种高级编程语言&#xff0c;其内存管理和函数调用机制包括递归、堆与栈。本文将详细讲解这三者的工作原理、用途以及它们在C#中的实现和应用。 1. 递归 (Recur…...

声音分离人声和配乐-从头设计数字生命第5课, demucs——仙盟创梦IDE

demucs 伴奏提取人声分离技术具有多方面的重大意义&#xff0c;主要体现在以下几个领域&#xff1a; 音乐创作与制作 创作便利性提升&#xff1a;创作者能轻易获取无伴奏的人声轨道&#xff0c;便于对人声进行单独处理&#xff0c;如调整音准、音色、添加特效等&#xff0c…...

基于PHP+Uniapp的互联网医院源码:电子处方功能落地方案

随着“互联网医疗”政策红利持续释放&#xff0c;互联网医院已成为推动医疗数字化转型的重要方向。在这一趋势下&#xff0c;电子处方功能模块作为核心环节&#xff0c;不仅直接关系到线上问诊闭环的实现&#xff0c;也成为系统开发中技术难度较高、业务逻辑最为复杂的一部分。…...

Linux 基础命令入门指南

在 Linux 系统中&#xff0c;命令行是高效操作和管理系统的核心方式。掌握一些基础命令&#xff0c;能够让我们更便捷地完成文件操作、系统监控、文本处理等任务。本文将为大家介绍常用的 Linux 基础命令&#xff0c;帮助新手快速入门。 一、文件和目录操作命令 1. ls&#x…...

(done) 吴恩达版提示词工程 3. 迭代 (控制输出长度、提取特定细节、输出 HTML 格式)

url: https://www.bilibili.com/video/BV1Z14y1Z7LJ?spm_id_from333.788.videopod.episodes&vd_source7a1a0bc74158c6993c7355c5490fc600&p3 别人的笔记 url: https://zhuanlan.zhihu.com/p/626966526 3. 迭代&#xff08;Iterative&#xff09; 当我使用大语言模型…...

学员答题pk知识竞赛小程序怎么做

制作学员答题PK知识竞赛小程序&#xff0c;主要有以下步骤&#xff1a; 一、规划设计 明确需求&#xff1a;确定小程序的使用场景是校园知识竞赛、培训机构考核还是企业内部培训等。答题功能&#xff0c;规定答题的具体规则&#xff0c;包括题目类型&#xff08;单选、多选、…...

P1217 [USACO1.5] 回文质数 Prime Palindromes【python】

P1217 [USACO1.5] 回文质数 Prime Palindromes 题目描述 因为 151 151 151 既是一个质数又是一个回文数&#xff08;从左到右和从右到左是看一样的&#xff09;&#xff0c;所以 151 151 151 是回文质数。 写一个程序来找出范围 [ a , b ] ( 5 ≤ a < b ≤ 100 , 000 …...

搭建私人网站

第一章 阿里云服务器选购与配置 1.1 注册与实名认证 ‌注册账号‌ 访问阿里云官网&#xff0c;点击右上角"免费注册"&#xff0c;填写邮箱/手机号&#xff0c;完成人机验证后获取验证码。 注意&#xff1a;企业用户需选择"企业实名认证"&#xff0c;个人用…...