【Rust trait特质】如何在Rust中使用trait特质,全面解析与应用实战
✨✨ 欢迎大家来到景天科技苑✨✨
🎈🎈 养成好习惯,先赞后看哦~🎈🎈
🏆 作者简介:景天科技苑
🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。
🏆《博客》:Rust开发,Python全栈,Golang开发,云原生开发,PyQt5和Tkinter桌面开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi,flask等框架,云原生K8S,linux,shell脚本等实操经验,网站搭建,数据库等分享。所属的专栏:Rust语言通关之路
景天的主页:景天科技苑
文章目录
- Rust trait(特征)
- 1. Trait基础概念
- 1.1 什么是Trait
- 1.2 Trait与接口的区别
- 1.3 Trait的基本语法
- 2. Trait实现与使用
- 2.1 为类型实现Trait
- 2.2 Trait的多种用法
- 1. Trait作为参数
- 2. 默认实现
- 3. Trait Bound泛型约束
- 4. trait作为返回值
- 5. 注意事项
- 3. 标准库中的常用Trait
- 3.1 格式化相关Trait
- 3.2 转换Trait
- 3.3 运算符重载Trait
- 3.4 其他比较重要的内置trait
Rust trait(特征)
1. Trait基础概念
1.1 什么是Trait
在Rust中,Trait是一种定义共享行为的机制,类似于其他语言中的"接口"(interface)或"抽象类"(abstract class)。
Trait允许我们定义一组方法签名,这些方法可以被不同类型实现,从而实现多态行为。
1.2 Trait与接口的区别
虽然Trait类似于接口,但Rust的Trait更加灵活和强大:
关联类型:Trait可以定义关联类型
默认实现:方法可以有默认实现
Trait对象:支持动态分发
条件实现:可以根据类型参数有条件地实现Trait
1.3 Trait的基本语法
定义Trait的基本语法如下:
trait里面定义各种方法
trait TraitName {fn method1(&self, ...) -> ReturnType;fn method2(&mut self, ...) -> ReturnType;// 可以有默认实现fn method_with_default(&self) {println!("Default implementation");}
}
使用 trait 关键字来声明一个 trait,后面是 trait 的名字,在这个例子中是 TraitName 。
在大括号中声明描述实现这个trait 的类型所需要的行为的方法,在这个例子中有三个方法 。
在方法签名后跟分号,而不是在大括号中提供其实现。
接着每一个实现这个 trait 的类型都需要提供其自定义行为的方法体,编译器也会确保任何实现TraitName trait 的类型都拥有与这个签名的定义完全一致的方法。
trait 体中可以有多个方法,一行一个方法签名且都以分号结尾。
2. Trait实现与使用
2.1 为类型实现Trait
我们可以为任何类型实现Trait,包括标准库类型和我们自定义的类型。
实现trait
impl 关键字之后,我们提供需要实现 trait 的名称,接着是for 和需要实现 trait 的 类型的名称。
在 impl 块中,使用 trait 定义中的方法签名,不过不再后跟分号,而是需要在大括号中编写函数体来为特定类型实现 trait 方法所拥有的行为。
语法如下:
impl trait for 类型名 {}
注意:实现 trait时,方法的签名必须与 trait 中定义的方法一致。trait 中的方法签名包括方法名、参数类型和返回值类型。
实现trait,必须将trait中的方法全部实现,默认实现的方法除外
不能自定义方法的签名
//定义一个 trait 和一个实现了该 trait 的结构体
// 这个 trait 定义了一个方法 say_hello
// 结构体 Person 实现了这个 trait
// 通过实现 trait 的方法,我们可以在结构体实例上调用这个方法
// 这个例子展示了如何使用 trait 来定义行为
// 以及如何在结构体中实现这些行为
// 通过 trait,我们可以定义一组方法的签名
// 然后在不同的结构体中实现这些方法
// 这使得代码更加灵活和可扩展
// 通过 trait,我们可以实现多态
trait Greet {fn say_hello(&self);fn say_goodbye(&self);
}// 定义一个结构体 Person
struct Person {name: String,
}// 实现 trait Greet 的方法
// 为结构体 Person 实现 trait Greet
// 通过实现 trait 的方法,我们可以在结构体实例上调用这个方法
impl Greet for Person {//注意:实现 trait时,方法的签名必须与 trait 中定义的方法一致。trait 中的方法签名包括方法名、参数类型和返回值类型。//不能自定义方法的签名fn say_hello(&self) {println!("Hello, my name is {}!", self.name);}fn say_goodbye(&self) {println!("Goodbye, {}!", self.name);}
}fn main() {// 创建一个 Person 实例let alice = Person { name: "jingtian".to_string() };// 调用 trait 中定义的方法// 通过结构体实例调用 trait 中的方法alice.say_hello(); // 输出: Hello, my name is Alice!alice.say_goodbye(); // 输出: Goodbye, Alice!
}
2.2 Trait的多种用法
1. Trait作为参数
传参的时候,我们并不知道item的具体类型
但是我们知道它实现了Summary这个trait
所以我们可以把它当做Summary来使用
只要某个类,实现了这个特征,这个类的实例就可以调用特征里面的方法
trait Summary {fn summarize(&self) -> String;fn summarize_author(&self) -> String;// 可以有默认实现fn summarize_default(&self) -> String {format!("(Read more from {}...)", self.summarize_author())}
}struct NewsArticle {headline: String,location: String,
}
impl Summary for NewsArticle {fn summarize(&self) -> String {format!("{} - {}", self.headline, self.location)}fn summarize_author(&self) -> String {String::from("jingtian")}
}//trait作为参数
//传参的时候,我们并不知道item的具体类型
//但是我们知道它实现了Summary这个trait,实现了这个特征的类型的对象,就可以作为参数传进来
//所以我们可以把它当做Summary来使用
fn notify(item: &impl Summary) {println!("Breaking news! {}", item.summarize());
}fn main() {println!("Hello, world!");//调用 trait 作为参数的函数let article = NewsArticle {headline: String::from("Rust is awesome!"),location: String::from("San Francisco"),};notify(&article);//调用 trait 的默认实现println!("{}", article.summarize_default());
}
2. 默认实现
trait的默认实现,就是在定义trait的时候,将里面的函数体写出来,而不是简单的只定义一个函数签名
这样,当某个类型实现了这个trait,不用再去写具体的方法内容,就可以调用这个trait的方法
Trait方法可以有默认实现,实现者可以选择使用默认实现或覆盖它。
有时为 trait 中的某些或全部方法提供默认的行为,而不是在每个类型的每个实现中都定义自己的行为是很有用的。
这样当为某个特定类型实现 trait 时,可以选择保留或重载每个方法的默认行为。
//trait的默认实现
trait Summary {fn summarize(&self) -> String;fn summarize_author(&self) -> String;// 在定义trait的时候,就将方法体给实现的方法,称为默认实现fn summarize_default(&self) -> String {format!("(Read more from {}...)", self.summarize_author())}
}struct NewsArticle {headline: String,location: String,
}//可以看到我们实现trait的时候,并没有实现默认的方法
// 但是我们可以直接使用默认的方法
// 这就是 trait 的默认实现的好处
impl Summary for NewsArticle {fn summarize(&self) -> String {format!("{} - {}", self.headline, self.location)}fn summarize_author(&self) -> String {String::from("jingtian")}
}fn main() {let article = NewsArticle {headline: String::from("Rust is awesome!"),location: String::from("San Francisco"),};println!("{}", article.headline);println!("{}", article.location);//调用实现了 trait 的方法println!("实现了的方法: {}", article.summarize());//调用 trait的默认实现println!("trait的默认实现: {}", article.summarize_default());
}
当然,我们也可以不使用默认的实现,将默认的实现给改成自己的实现
将默认实现的函数重写
//trait的默认实现
trait Summary {fn summarize(&self) -> String;// 可以有默认实现fn summarize_author(&self) -> String;fn summarize_default(&self) -> String {format!("(Read more from {}...)", self.summarize_author())}
}struct NewsArticle {headline: String,location: String,
}//可以看到我们实现trait的时候,并没有实现默认的方法
// 但是我们可以直接使用默认的方法
// 这就是 trait 的默认实现的好处
impl Summary for NewsArticle {fn summarize(&self) -> String {format!("{} - {}", self.headline, self.location)}fn summarize_author(&self) -> String {String::from("jingtian")}//将默认实现的函数重写fn summarize_default(&self) -> String {format!("(Read more from {}...)", "jingtian".to_string())}
}fn main() {let article = NewsArticle {headline: String::from("Rust is awesome!"),location: String::from("San Francisco"),};println!("{}", article.headline);println!("{}", article.location);//调用实现了 trait 的方法println!("实现了的方法: {}", article.summarize());//调用 重载后的实现println!("trait的默认实现: {}", article.summarize_default());
}
此时,就是我们重载后的方法实现
这样其实就是实现了多态
3. Trait Bound泛型约束
Rust 中的 trait bound 是一种对泛型类型添加约束的机制,用来确保某个类型实现了特定的 trait,这样我们就可以在函数或结构体中安全地使用该 trait 的方法或功能。
📘 1)什么是 trait bound?
在 Rust 中,trait 类似于其他语言中的接口,它定义了一组方法签名。trait bound 就是用来约束泛型类型必须实现某个 trait 的方式。
示例1:
// 定义一个 trait
trait Printable {fn print(&self);
}// 使用 trait bound 约束 T 必须实现 Printable
fn print_item<T: Printable>(item: T) {item.print();
}
示例2:
//trait bound
// trait bound 是 Rust 中的一种语法,用于指定泛型类型参数必须实现某个 trait
// trait bound 可以用于函数、结构体、枚举等的定义中
// trait bound 的语法是:<T: Trait>,其中 T 是泛型类型参数,Trait 是 trait 的名称
// trait bound 的作用是限制泛型类型参数的类型,使得在使用泛型时,编译器可以检查泛型类型参数是否实现了指定的 trait
trait Summary {fn summarize(&self) -> String;
}
struct NewsArticle {headline: String,location: String,
}
impl Summary for NewsArticle {fn summarize(&self) -> String {format!("{} - {}", self.headline, self.location)}
}fn notify(item: &impl Summary) {println!("Breaking news! {}", item.summarize());
}
//使用 trait bound简写
//约束,只有实现了Summary trait的类型才能作为参数传入
fn notify_bound<T: Summary>(item: &T) {println!("trait_bound Breaking news! {}", item.summarize());
}fn main() {let article = NewsArticle {headline: String::from("Rust is awesome!"),location: String::from("San Francisco"),};//调用 trait 作为参数的函数notify(&article);//调用 trait bound 的函数notify_bound(&article);
}
🧩 2)trait bound 的几种语法
- 简写语法:T: Trait
fn do_something<T: Trait1 + Trait2>(val: T) {// T 实现了 Trait1 和 Trait2
}
- where 语法(更清晰,适用于复杂约束)
fn do_something<T, U>(t: T, u: U)
whereT: Trait1 + Trait2,U: Trait3,
{// 可以使用 T 和 U 的 trait 方法
}
- 用于结构体或枚举中
struct Wrapper<T: Printable> {value: T,
}
或者使用 where:
struct Wrapper<T>
whereT: Printable,
{value: T,
}
🛠️ 3)trait bound 的常见用途
- 约束泛型函数
fn compare<T: PartialOrd>(a: T, b: T) -> T {if a < b { a } else { b }
}
- 实现泛型 trait
impl<T: Display> ToString for Wrapper<T> {fn to_string(&self) -> String {format!("{}", self.value)}
}
- 配合 impl Trait 简化语法(Rust 2018+)
fn print_item(item: impl Printable) {item.print();
}
这等价于 fn print_item<T: Printable>(item: T)
。
🛠️ 4)通过 trait bound 有条件地实现方法
在 Rust 中,可以通过 Trait Bound 为泛型类型有条件地实现方法,这意味着只有当类型满足特定约束时,这些方法才可用。
这是一种非常强大的模式,允许你为特定类型的子集提供额外功能。
通过使用带有 trait bound 的泛型 impl 块,可以有条件的只为实现了特定 trait 的类型实现方法。
基本语法
struct Wrapper<T>(T);// 为所有类型 T 实现的方法
impl<T> Wrapper<T> {fn new(value: T) -> Self {Wrapper(value)}
}// 只为实现了 Display 的类型 T 实现的方法
impl<T: std::fmt::Display> Wrapper<T> {fn display(&self) {println!("Wrapper contains: {}", self.0);}
}
实际应用示例
- 为实现了特定 trait 的类型添加方法
use std::fmt::Debug;struct Printer<T>(T);// 无条件实现的方法
impl<T> Printer<T> {fn new(value: T) -> Self {Printer(value)}
}//有条件实现的方法
// 这里的 T 必须实现 Debug trait
// 这意味着我们可以在这个方法中使用 {:?} 来打印 T 的值
// 这使得我们可以在实现方法时,限制 T 的类型
// 只有实现了 Debug trait 的类型才能使用这个方法
// 这就是 trait bound 的作用
// 只为实现了 Debug 的类型实现的方法
//当然,也可以实现我们自定义的trait
impl<T: Debug> Printer<T> {fn print(&self) {println!("{:?}", self.0);}
}fn main() {let p1 = Printer::new(42); // i32 实现了 Debugp1.print(); // 可以调用 printlet p2 = Printer::new(vec![1, 2, 3]); // Vec 实现了 Debugp2.print(); // 可以调用 printstruct MyType; // 未实现 Debuglet p3 = Printer::new(MyType);p3.print(); // 编译错误:MyType 未实现 Debug
}
- 为实现了多个 trait 的类型实现方法
use std::fmt::{ Display, Debug };//元组结构体
// 这个结构体可以存储任何类型的值
// 只要它们实现了 Display 和 Debug trait
// 这个结构体的作用是将值打印出来
// 这个结构体的泛型参数 T 可以是任何类型
struct MultiPrinter<T>(T);impl<T> MultiPrinter<T> {fn new(value: T) -> Self {MultiPrinter(value)}
}// 要求同时实现 Display 和 Debug
impl<T: Display + Debug> MultiPrinter<T> {fn print_all(&self) {println!("Display: {}", self.0);println!("Debug: {:?}", self.0);}
}fn main() {let printer = MultiPrinter::new("Hello, world!");printer.print_all();let printer2 = MultiPrinter::new(42);printer2.print_all();
}
🛠️ 4)有条件地实现trait
可以对任何实现了特定 trait 的类型有条件的实现 trait。
对任何满足特定 trait bound 的类型实现 trait 被称为 blanket implementations,他们被广泛的用于 Rust 标准库中。
类似于其他语言的继承
例如,标准库为任何实现了 Display trait 的类型实现了 ToString trait。这个 impl 块看起来像这样:
impl<T: Display> ToString for T {// --snip--
}
因为标准库有了这些 blanket implementation,我们可以对任何实现了 Display trait 的类型调用由 ToString 定义的to_string 方法。
例如,可以将整型转换为对应的 String 值,因为整型实现了 Display :
let s = 3.to_string();
blanket implementation 会出现在 trait 文档的 “Implementers” 部分。
trait 和 trait bound 让我们使用泛型类型参数来减少重复,并仍然能够向编译器明确指定泛型类型需要拥有哪些行为。
因为我们向编译器提供了 trait bound 信息,它就可以检查代码中所用到的具体类型是否提供了正确的行为。
在动态类型语言中,如果我们尝试调用一个类型并没有实现的方法,会在运行时出现错误。
Rust 将这些错误移动到了编译时,甚至在代码能够运行之前就强迫我们修复错误。
另外,我们也无需编写运行时检查行为的代码,因为在编译时就已经检查过了,这样相比其他那些不愿放弃泛型灵活性的语言有更好的性能。
基本语法
impl<T: TraitBound> MyTrait for T {// 实现方法
}
或者使用 where 子句:
impl<T> MyTrait for T
whereT: Trait1 + Trait2,
{// 实现方法
}
常见应用模式
- 为实现了其他 trait 的类型实现你的 trait
use std::fmt::Display;trait Printable {fn print(&self);
}// 为所有实现了 Display 的类型自动实现 Printable
impl<T: Display> Printable for T {fn print(&self) {println!("{}", self);}
}fn main() {(42).print(); // 可以调用,因为 i32 实现了 Display"hello".print(); // 可以调用,因为 &str 实现了 Display
}
只要实现了Display的类型,都会自动实现我们自定义的trait Printable
其实例就可以调用print方法
- 为特定类型组合实现 trait
trait Greet {fn greet(&self);
}struct Person;
struct Dog;// 只为 Person 实现 Greet
impl Greet for Person {fn greet(&self) {println!("Hello!");}
}// 有条件地为某些泛型类型实现 Greet
// 实现Greet的T,Vec<T>也实现了Greet
impl<T> Greet for Vec<T> where T: Greet {fn greet(&self) {for item in self {item.greet();}}
}fn main() {let person = Person;person.greet(); // 正常调用let people = vec![Person, Person];people.greet(); // 调用 Vec 的实现// let dogs = vec![Dog, Dog];// dogs.greet(); // 编译错误,因为 Dog 没有实现 Greet
}
🧠 6)使用 trait bound 的好处
类型安全:编译时就能检查类型是否满足要求。
泛型复用:编写更通用的代码。
自动推导实现:结合 derive 宏可以快速添加常用 trait(如 Debug, Clone 等)。
4. trait作为返回值
在 Rust 中,trait 不能直接作为函数返回值的类型,因为 trait 是一个抽象类型(即它本身没有大小,Sized)。
但我们可以通过两种方式让函数 “返回一个实现了 trait 的值”:
1)使用 impl Trait 作为返回类型(静态分发 ✅)
impl Trait 作为返回类型时,函数必须返回单一的具体类型,不能根据条件返回不同类型。
返回impl Trait,其实就是返回实现了这个特征的类型对象
//trait作为返回值
// trait 作为返回值
// trait 作为返回值是 Rust 中的一种用法,可以让函数返回实现了某个 trait 的类型
// trait 作为返回值的语法有两种:
//一种是静态发布,返回特征的实现 fn function_name() -> impl Trait
//一种是动态发布,fn function_name() -> Box<dyn Trait>,其中 Box<dyn Trait> 是一个 trait 对象
// trait 对象是一个指向实现了 trait 的类型的指针
// trait 对象可以在运行时动态地决定具体的类型trait Animal {fn speak(&self) -> String;
}struct Dog;impl Animal for Dog {fn speak(&self) -> String {"Woof!".to_string()}
}// 返回一个实现了 Animal 的具体类型(静态分发)
//返回值是个特征的实现的时候,就是返回实现了这个特征的对象
fn get_animal() -> impl Animal {Dog
}fn main() {let animal = get_animal();println!("{}", animal.speak());
}
2)使用 Box 返回 trait 对象(动态分发 ✅)
使用 trait 对象 (dyn Trait) 返回多种类型
//trait作为返回值
// trait 作为返回值
// trait 作为返回值是 Rust 中的一种用法,可以让函数返回实现了某个 trait 的类型
// trait 作为返回值的语法是:fn function_name() -> Box<dyn Trait>,其中 Box<dyn Trait> 是一个 trait 对象
// trait 对象是一个指向实现了 trait 的类型的指针
// trait 对象可以在运行时动态地决定具体的类型
// trait 对象的大小是固定的,可以在运行时动态地决定具体的类型trait Animal {fn speak(&self) -> String;
}struct Dog;
struct Cat;impl Animal for Cat {fn speak(&self) -> String {"Meow!".to_string()}
}impl Animal for Dog {fn speak(&self) -> String {"Woof!".to_string()}
}//动态发布
fn dyget_animal(choice: u8) -> Box<dyn Animal> {if choice == 0 { Box::new(Dog) } else { Box::new(Cat) }
}fn main() {let animal = dyget_animal(0);println!("{}", animal.speak());let animal = dyget_animal(1);println!("{}", animal.speak());}
这是 trait 作为返回值的“对象安全”用法。
✅ 优点:
可以返回不同的具体类型(如 Dog 或 Cat)
灵活性更高
⚠️ 限制:
动态分发,运行时有一点性能开销
需要 dyn Trait 是对象安全(只能包含不依赖于 Self 的方法,且不能有泛型)
注意事项
对象安全:当使用 dyn Trait 时,trait 必须是对象安全的
不能有返回 Self 的方法
不能有泛型方法
生命周期:trait 对象默认有 'static 生命周期,如果需要更短的生命周期需要明确指定
两种方法比较
5. 注意事项
孤儿规则:实现 trait 时,必须保证 trait 或类型至少有一个是在当前 crate 中定义的
特化限制:Rust 目前不支持完全的 trait 实现特化
方法优先级:更具体的实现会覆盖更通用的实现
冲突实现:避免创建会导致编译器无法确定使用哪个实现的场景
文档:为条件实现添加清晰的文档说明
3. 标准库中的常用Trait
3.1 格式化相关Trait
Display:用户友好的展示
Debug:调试输出
LowerHex:十六进制小写格式化
use std::fmt;struct Point {x: i32,y: i32,
}//让自己实现的类型实现 Display 和 Debug trait
// 通过实现 fmt::Display trait 来实现格式化输出
// 通过实现 fmt::Debug trait 来实现调试输出
impl fmt::Display for Point {fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {write!(f, "({}, {})", self.x, self.y)}
}impl fmt::Debug for Point {fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {f.debug_struct("Point").field("x", &self.x).field("y", &self.y).finish()}
}fn main() {let p = Point { x: 1, y: 2 };println!("Display: {}", p);println!("Debug: {:?}", p);
}
3.2 转换Trait
From/Into:类型转换
TryFrom/TryInto:可能失败的转换
AsRef/AsMut:引用转换
struct Inches(f64);
struct Millimeters(f64);impl From<Millimeters> for Inches {fn from(mm: Millimeters) -> Self {Inches(mm.0 / 25.4)}
}fn print_inches(inches: Inches) {println!("{} inches", inches.0);
}fn main() {let mm = Millimeters(254.0);let inches: Inches = mm.into();print_inches(inches); // 输出: 10 inches
}
3.3 运算符重载Trait
Add/Sub/Mul/Div:算术运算
Neg:一元负号
Index/IndexMut:索引操作
use std::ops::{ Add, Mul };
struct Vector {x: f64,y: f64,
}impl Add for Vector {type Output = Vector;fn add(self, other: Vector) -> Vector {Vector {x: self.x + other.x,y: self.y + other.y,}}
}impl Mul<f64> for Vector {type Output = Vector;fn mul(self, scalar: f64) -> Vector {Vector {x: self.x * scalar,y: self.y * scalar,}}
}fn main() {let v1 = Vector { x: 1.0, y: 2.0 };let v2 = Vector { x: 3.0, y: 4.0 };let v3 = v1 + v2;println!("v3: ({}, {})", v3.x, v3.y);let scalar = 2.0;let v4 = v3 * scalar;println!("v4: ({}, {})", v4.x, v4.y);
}
3.4 其他比较重要的内置trait
Clone: 显式复制对象
Copy: 标记类型可以在赋值时进行位复制
PartialEq/Eq: 相等比较
PartialOrd/Ord: 排序比较
Default: 创建默认值
Iterator: 迭代器
Drop: 自定义析构逻辑
相关文章:
【Rust trait特质】如何在Rust中使用trait特质,全面解析与应用实战
✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,…...
滑动窗口算法笔记
力扣209 题目分析:想象一个窗口遍历着这个数组,不断扩大右边界,让r。往窗口中添加数字: 此时我们找到了这个窗口,它的和满足了大于等于target的条件,题目让我求最短的,那么我们就尝试来缩短它&…...
Problem A: 歌手打分
1.题目描述 在歌唱比赛中,共有10位评委进行打分,在计算歌手得分时,去掉一个最高分,去掉一个最低分,然后剩余的8位评委的分数进行平均,就是该选手的最终得分。输入每个评委的评分,求某选手的得分…...
容器安全-核心概述
文章摘要 本文探讨了容器安全的四个核心类别,包括环境基础设施安全、镜像安全、运行时安全和生态安全。尽管 EDR 能提供主机安全层面的部分防护,但无法覆盖容器的镜像安全和生态安全。容器的镜像安全和生态安全问题,如镜像漏洞、恶意镜像、容…...
Golang实践录:在go中使用curl实现https请求
之前曾经在一个 golang 工程调用 libcur 实现 https的请求,当前自测是通过的。后来迁移到另一个小系统出现段错误,于是对该模块代码改造,并再次自测。 问题提出 大约2年前,在某golang项目使用libcurl进行https请求(参…...
nvrtc环境依赖
一 下载 1.1 添加nvidia的源(不同于pypi) pip install nvidia-pyindex 1.2 pip dowload 执行 pip download nvidia-cuda-runtime nvidia-cuda-python 会发现文件夹多了以下几个文件 而需要安装的则只有红框的三个文件, 二 安装 对红框的…...
【计算机视觉】OpenCV实战项目:GraspPicture 项目深度解析:基于图像分割的抓取点检测系统
GraspPicture 项目深度解析:基于图像分割的抓取点检测系统 一、项目概述项目特点 二、项目运行方式与执行步骤(一)环境准备(二)项目结构(三)执行步骤 三、重要逻辑代码解析(一&#…...
Redis持久化存储
我们知道Redis是将数据放在内存中的,那怎么做到持久化存储呢?很简单,就是内存存一份,硬盘也存一份.那么两个地方都存会不会影响效率?答案是影响是不大的,要看具体的策略.同时也要注意内存的数据和硬盘中的数据可能会有一点不同.这也是取决于策略的不同. Redis持久化存储的两个…...
网络检测工具InternetTest v8.9.1.2504 单文件版,支持一键查询IP/DNS、WIFI密码信息
—————【下 载 地 址】——————— 【本章下载一】:https://drive.uc.cn/s/295e068b79314 【本章下载二】:https://pan.xunlei.com/s/VOQDXguH0DYPxrql5y2zlkhTA1?pwdg2nx# 【百款黑科技】:https://ucnygalh6wle.feishu.cn/wiki/…...
elpis-core: 基于 Koa 实现 web 服务引擎架构设计解析
前言 内容来源于抖音【哲玄前端】大佬的《大前端全栈实践》课程,此课程是从零开始做一个企业级的全栈应用框架。此框架是基于koa.js构建的服务引擎,对BFF层的框架封装,让我感受颇深。 整体elpis项目架构设计 elpis-core设计思路 可以看到elpi…...
计算机网络-MPLS LDP基础实验配置
前面我们学习了LDP的会话建立、标签发布与交换、LDP的工作原理,今天通过一个基础实验来加深记忆。 一、LDP基础实验 实验拓扑: 1、IGP使用OSPF进行通告,使用Lookback接口作为LSR ID,LDP ID自动生成。 2、实验目的:使…...
搜索二维矩阵 II
存储m和n,用i表示行,j表示列,i从最后一行开始遍历,j从0开始遍历,当前值比目标值小j,反之i-- class Solution { public:bool searchMatrix(vector<vector<int>>& matrix, int target) {int…...
C++中如何实现一个单例模式?
单利模式是指对象在整个程序中只有一个实例,提供一个访问方法供全局访问。实现单例模式有如下要求: 1.私有化构造函数:将构造函数定义为私有,以防外部通过构造函数创建其它实例。 2.静态实例:在内部提供一个静态实例…...
进程与线程
进程与线程:计算机世界的"公司与员工" 进程与线程的本质区别 进程(Process)是计算机中独立运行的程序实例,拥有自己的内存空间和系统资源;而线程(Thread)是进程内的执行单元,共享所属进程的资源,但拥有独立的执行路径。 🏢 生活类比:想象一个大型企业的运…...
JDK 命令行工具大全与学习方法总结 —— 从帮助文档到高效实践
JDK 命令行工具大全与学习方法总结 —— 从帮助文档到高效实践 Java开发与运维过程中,JDK自带的命令行工具是定位问题、性能调优、编译调试的基石。本文全面梳理JDK常用命令工具、帮助文档的获取方式,并总结类似Linux命令行的学习方法,助你系…...
行业趋势与技术创新:驾驭工业元宇宙与绿色智能制造
引言 制造业发展的新格局:创新势在必行 当今制造业正经历深刻变革,面临着供应链波动、个性化需求增长、可持续发展压力以及技能人才短缺等多重挑战。在这样的背景下,技术创新不再是可有可无的选项,而是企业保持竞争力、实现可持…...
代码随想录算法训练营第三十九天(打家劫舍专题) | 198.打家劫舍、213.打家劫舍II、337.打家劫舍III
一、198.打家劫舍 题目链接:198. 打家劫舍 - 力扣(LeetCode) 文章讲解:代码随想录 视频讲解:动态规划,偷不偷这个房间呢?| LeetCode:198.打家劫舍_哔哩哔哩_bilibili 1. 思路 大家如…...
Linux514 rsync 解决方案环境配置
节点ab都改为NAT模式 网关和VMnet8网卡不一致 ping 不通外网 ping不通外网 是这里的问题吗 怎么突然就ping通了 没改啥啊 上面改了dhcp范围后 ping还是ping不通 为啥现在又ping通了 设置节点b 推测应该是dhcp范围问题 今日源码 节点b MX...
STM32F103_LL库+寄存器学习笔记23 - PWM波形输出及软件方式调整周期与占空比
导言 脉宽调制(PWM)是 STM32 定时器最常用的输出模式之一,广泛应用于电机驱动、LED 调光、伺服控制和功率管理等场景。本篇文章将以 TIM5 为例,从寄存器层面深入剖析 PWM 输出的原理与实现步骤。通过本篇博客,你不仅能…...
Canvas知识框架
一、Canvas基础 核心概念 Canvas是位图绘图区域,通过JavaScript(或Python等)动态绘制图形。 坐标系:左上角为原点 (0, 0),x向右递增,y向下递增。 绘图流程: const canvas document.getElemen…...
【SSL证书系列】客户端如何验证https网站服务器发的证书是否由受信任的根证书签发机构签发
客户端验证HTTPS网站证书是否由受信任的根证书颁发机构(CA)签发,是一个多步骤的过程,涉及证书链验证、信任锚(Trust Anchor)检查、域名匹配和吊销状态验证等。以下是详细的验证流程: 1. 证书链的…...
spark小任务
import org.apache.spark.{Partitioner, SparkConf, SparkContext}object PartitionCustom {// 分区器决定哪一个元素进入某一个分区// 目标: 把10个分区器,偶数分在第一个分区,奇数分在第二个分区// 自定义分区器// 1. 创建一个类继承Partitioner// 2. …...
git push 报错:send-pack: unexpected disconnect while reading sideband packet
背景 新建了一个仓库,第一次push 代码文件,文件中有一个依赖的jar,有80MB,结果push的时候报错。 错误信息 error: RPC failed; HTTP 500 curl 22 The requested URL returned error: 500 send-pack: unexpected disconnect whi…...
读入csv文件写入MySQL
### 使用 Spark RDD 读取 CSV 文件并写入 MySQL 的实现方法 #### 1. 环境准备 在使用 Spark 读取 CSV 文件并写入 MySQL 数据库之前,需要确保以下环境已配置完成: - 添加 Maven 依赖项以支持 JDBC 连接。 - 配置 MySQL 数据库连接参数,包括 …...
5.18-AI分析师
强化练习1 神经网络训练案例(SG) #划分数据集 #以下5行需要背 folder datasets.ImageFolder(rootC:/水果种类智能训练/水果图片, transformtrans_compose) n len(folder) n1 int(n*0.8) n2 n-n1 train, test random_split(folder, [n1, n2]) #训…...
腾讯云运营开发 golang一面
redis为什么单线程会快 每秒10w吞吐量 io多路复用 一个文件描述符整体拷贝;调用epoll_ctl 单个传递 内核遍历文件描述符判断是否有事件发送;回调函数列表维护 修改有事件发送的socket为可读或可写,返回整个文件描述符;返回链…...
spark数据压缩
### Spark 数据压缩方法及其实现 在大数据处理框架中,数据压缩是一个重要的环节,它不仅能够减少磁盘占用空间,还能降低网络传输成本。然而,在分布式计算环境中(如 Spark),选择合适的压缩编解码…...
synchronized关键字详解
synchronized关键字详解 1. 基本概念与使用方式 作用:确保多个线程在访问共享资源时的互斥性,防止数据不一致。使用方式: 修饰实例方法:锁对象为当前实例(this)。public synchronized void instanceMethod() {// 同步代码 }修饰静态方法:锁对象为类的Class对象。public…...
React useState 的同步/异步行为及设计原理解析
一、useState 的同步/异步行为 异步更新(默认行为) • 场景:在 React 合成事件(如 onClick)或生命周期钩子(如 useEffect)中调用 useState 的更新函数时,React 会将这些更新放入队列…...
《社交应用动态表情:RN与Flutter实战解码》
React Native依托于JavaScript和React,为动态表情的实现开辟了一条独特的道路。其核心优势在于对原生模块的便捷调用,这为动态表情的展示和交互提供了强大支持。在社交应用中,当用户点击发送动态表情时,React Native能够迅速调用相…...
【Oracle专栏】清理告警日志、监听日志
Oracle相关文档,希望互相学习,共同进步 风123456789~-CSDN博客 1.背景 今天在导入数据库时,发现之前可以导入,今天导入时居然报空间不足,于是检查是哪里占用空间比较大。检查回收站、归档日志,发现没有。然后检查告警日志、监听日志,发现果然占用空间比较大,于是进行…...
Ubuntu24.04编译ORB_SLAM的一系列报错解决
Ubuntu24.04编译ORB_SLAM的一系列报错解决 decay_t报错 报错信息:error: ‘decay_t’ is not a member of ‘std’;did you mean ‘decay’ 将CMakeLists.txt中第17行的c标准修改为c14即可: 修改前: CHECK_CXX_COMPILER_FLAG…...
Python × CARLA:如何在自动驾驶仿真世界里打造智能驾驶系统?
Python CARLA:如何在自动驾驶仿真世界里打造智能驾驶系统? 在人工智能与自动驾驶的浪潮中,真实世界的测试成本高昂,而自动驾驶仿真已成为开发者训练和测试 AI 驾驶算法的关键技术手段。其中,CARLA(Car Learning to Act)作为开源自动驾驶仿真平台,凭借其真实感强、高度…...
如何迁移 WSL 卸载 Ubuntu WSL
迁移 WSL 到其他盘区 假设您已经安装了 WSL 上的 Ubuntu 22.04 LTS,并且想要将其从 C 盘迁移到 D 盘。 查看 WSL 状态: 打开 PowerShell 或 CMD,运行以下命令查看当前安装的 WSL 发行版: wsl -l -v假设输出显示 Ubuntu-22.04 正在…...
【Linux】多路转接epoll、Linux高并发I/O多路复用
📚 博主的专栏 🐧 Linux | 🖥️ C | 📊 数据结构 | 💡C 算法 | 🅒 C 语言 | 🌐 计算机网络 上篇文章:五种IO模型与阻塞IO以及多路转接select机制编写echoserver 下篇文章…...
【taro3 + vue3 + webpack4】在微信小程序中的请求封装及使用
前言 正在写一个 以taro3 vue3 webpack4为基础框架的微信小程序,之前一直没有记咋写的,现在总结记录一下。uniapp vite 的后面出。 文章目录 前言一、创建环境配置文件二、 配置 Taro 环境变量三、 创建请求封装四、如何上传到微信小程序体验版1.第二…...
在python中使用Json提取数据
文章目录 一、前言二、格式转换2.1 dumps函数2.2 loads函数2.3 错误处理 三、JSONPath模块四、JMESPath模块4.1 search函数4.2 基本语法4.2.1 基本查询4.2.2 投影4.2.3 管道4.2.4 多选4.2.5 函数 一、前言 官方文档:https://docs.python.org/zh-cn/3.12/library/js…...
备战菊厂笔试4
目录 39.组合总和 回溯(单向剪枝) 3102.最小化曼哈顿距离 利用曼哈顿距离的性质 3163.压缩字符串3 46.全排列 53.最大子数组和 39.组合总和 39. 组合总和 注意: set不能添加list得加元组 元组不可修改 sorted后得赋值 class So…...
白盒测试——基本路径测试法
一、实验名称 白盒测试——基本路径测试法 二、实验目的 白盒测试是结构测试,是依据被测程序的内部逻辑结构设计测试用例,驱动被测程序运行完成的测试,通过本实验希望: 1、掌握基本路径测试法的基本概念,用具体的例子…...
FFmpeg 与 C++ 构建音视频处理全链路实战(五)—— 音视频编码与封装
在前面的系列文章中,我们已经层层深入,从 MP4 与 FLV 封装格式的剖析,到 H.264 和 AAC 原理的探索,再到 FFmpeg 的解封装、解码,以及音频重采样、视频尺寸变化的代码实现,为音视频处理打下了坚实基础。而今…...
NNLM神经网络语言模型总结
一开始还以为很复杂,总结一下就是: NNLM 将某个单词前 n−1 个词各自转为 embedding,拼接成一个 (n−1)⋅d 维的向量,再通过隐藏层 输出层 softmax,预测下一个词的概率分布 可以发现,这个2003年提出的模…...
开源Heygem本地跑AI数字人视频教程
图文教程: 点击跳转 视频教程 资料包下载 点击下载:...
软件验收测试有哪些流程?与确认测试又有什么不同?
随着信息技术的飞速发展,软件的应用覆盖面越来越广泛,软件验收测试的重要性也愈发显著。软件验收测试是指在软件开发完成后,对软件进行的最后一次全面审核,以确保软件的功能和性能满足用户需求。这一阶段通常由客户进行࿰…...
一文了解 HTTP Content-Type:从基础到实战
一文了解 HTTP Content-Type:从基础到实战 在 Web 开发中,HTTP 请求头中的 Content-Type 是一个看似简单却至关重要的概念。它决定了浏览器和服务器如何解析和处理传输的数据。本文将带你全面掌握 Content-Type 的核心知识,涵盖常见类型、应…...
数学建模初等模型应用
一、目的 掌握初等模型的建模方法,对简单的初等模型能借助Matlab工具软件进行辅助建模、求解和检验。 二、实验内容与设计思想(设计思路、主要代码分析) 1、预测鱼的质量 (1)设计思路:使用线性回归模型预测鱼的质量…...
map和unordered_map
一、map和unordered_map的基本概念——它们是啥? map:是一种“有序的关联容器”,存放一组“键值对”,内部元素按键排序(默认是升序),类似一本按字母排序的字典。 unordered_map:也是…...
【vue】脚手架
一、使用脚手架创建项目 1.打开编辑器终端 2.输入命令vue create 项目名 3.选择自定义配置,选以下几种常用的配置项(空格选中或删除) 二、常规操作 进入项目:cd 项目名 返回:cd .. 运行项目:npm run serve 停止项目:ct…...
PaddleNLP框架训练模型:使用SwanLab教程
PaddleNLP 是一款基于飞桨深度学习框架的大语言模型(LLM)开发套件,支持在多种硬件上进行高效的大模型训练、无损压缩以及高性能推理。PaddleNLP 具备简单易用和性能极致的特点,致力于助力开发者实现高效的大模型产业级应用。 你可以使用PaddleNLP快速进行…...
单向循环链表C语言实现实现(全)
#include<stdio.h> #include<stdlib.h> #define TRUE 1 #define FASLE 0//定义宏标识判断是否成功 typedef struct Node {int data;struct Node* next; }Node;Node* InitList() {Node* list (Node*)malloc(sizeof(Node));list->data 0;//创建节点保存datalist…...
数据结构:ArrayList简单实现与常见操作实例详解
目录 1.顺序表概念 2.自己实现 1.准备工作 接口 MyArrayList的定义 2.具体接口实现 添加 判满 扩容 查找 获得pos位置的值 和 更改pos位置的值 判空 删除 得到数组长度 清空数组 打印 3.ArrayList 1.简介 2.使用 1.ArrayList的构造 无参构造 有参构造&a…...