Rust 数据类型 之 结构体(Struct)

目录

结构体(Struct)

定义与声明

结构体定义

结构体实例

结构体分类

单元结构体(Unit Struct)

元组结构体(Tuple Struct)

具名结构体(Named Struct)

结构体嵌套

结构体方法

例1:结构体转换为字符串描述

例2:矩形的周长和面积

例3:结构体字段的更新与输出

关联函数

结构体方法与关联函数的区别

参数传递方式的区别

使用方式的区别

结构体的trait

#[derive(Debug)]

例1:

例2:

自定义打印宏 

1. impl fmt::Debug for Student

2. impl fmt::Display for Student

#[derive(PartialEq)]

例1:

例2:

#[derive(Default)]

例1:

例2:

#[derive(Clone)]

其他相关内容

模式匹配

例1:

例2:

结构体大小

1. std::mem::size_of

2. std::mem::size_of_val

本文总结


结构体(Struct)

是一种自定义数据类型,允许将多个相关的值组合在一起,形成一个更复杂的数据结构。结构体被广泛应用于组织和管理数据,具有灵活性和强大的表达能力。

定义与声明

结构体定义

在Rust中,定义和声明结构体的语法如下:

struct Name {  field1: Type1,  field2: Type2,  // ...  fieldN: TypeN,  
}

其中,Name是结构体的名称,每个数据名及其对应的数据类型组成一个字段,field1fieldN是结构体的字段名称,Type1TypeN是字段的数据类型

通过关键字 struct 定义,指定结构体名称,结构体内用 field:type, 表示字段名称及数据类型,注意rust语言不能在定义的同时进行赋值,且用逗号分隔各字段,不像c/c++用分号

结构体中可以根据需要定义字段个数,理论上要多少就定义多少;但实际上字段太多,结构体也会变得很占空间,对程序的空间效率是个负担。

结构体实例

如以下代码定义了一个名为Point的结构体,包含x和y两个字段,类型分别为i32和f64:

struct Point {
    x: i32,
    y: f64,
}

定义结构体后,可以像使用其他类型一样使用它。例如,可以声明一个Point类型的变量,并为其字段赋值

let my_point = Point { x: 10, y: 20.0 };

使用结构体时,用成员运算符 my_point.x 来调用对应字段的值:

println!("({},{})", point.x, point.y);    // 输出:(10,20)

可变实例

需要变动字段的值,在声明时需要用 let mut,如:

struct Point {  x: i32,  y: f64,  
}fn main() {let mut point = Point { x: 10, y: 20.0 }; point.x = 5;println!("({},{})", point.x, point.y);  // 输出:(5,20)
}

结构体分类

在Rust中,结构体(Struct)可以按照不同的方式进行分类,以下是一些常见的分类方式:

单元结构体(Unit Struct)

这种结构体没有任何字段,它只是用于表示一个空的类型。这种结构体通常用于作为其他结构体的组成部分或返回类型。例如:

struct UnitStruct;

元组结构体(Tuple Struct)

这种结构体包含一组字段,可以通过元组语法来访问每个字段。元组结构体可以用于表示简单的数据集合,不使用大括号{},而是使用元组的小括号()。例如:

struct TupleStruct(i32, String);

相当字段数据没有名称的结构体,访问时使用索引。如:

struct Point (i32, f64);fn main() {let mut point = Point(10, 20.0); point.0 = 5;println!("({},{})", point.0, point.1);  
}

具名结构体(Named Struct)

这种结构体有一个显式的名称,并且包含一组字段。具名结构体可以用于表示复杂的数据结构,例如一个包含多个字段的对象,本文的示例大多数都为具名结构体,用法已在本文开头讲过:

struct MyStruct {  
    field1: i32,  
    field2: String,  
    // ...  
}

除了以上三种常见的结构体类型,Rust还支持其他特殊类型的结构体,例如带有泛型参数的结构体、具名元组结构体(Named Tuple Struct)和结构体路径(Struct Type Alias)等。

需要注意的是,在Rust中,结构体的分类并不是强制性的,也就是说,一个结构体可以包含任意类型的字段,并且可以在任何地方使用。这使得结构体非常灵活,可以用于实现各种复杂的数据结构。

结构体字段的数据类型可以是以下常见的rust数据,甚至可以是函数、引用、指针类型。

  1. 标量类型(Scalar Types):

    • 整数类型(Integer Types):包括有符号整数类型和无符号整数类型。常见的整数类型有 i8i16i32i64i128 表示有符号整数,u8u16u32u64u128 表示无符号整数。此外,还有 isize 和 usize,它们根据平台的位数自动调整大小。
    • 浮点数类型(Floating-Point Number Types):包括 f32 和 f64 两种类型,表示单精度和双精度浮点数。
    • 布尔类型(Boolean Type):只有两个取值,true 和 false
    • 字符类型(Character Type):表示单个 Unicode 字符,通常存储为 4 个字节。
  2. 复合类型(Composite Types):

    • 数组类型(Array Types):由相同类型的元素组成的有限集合。可以通过固定长度或动态长度来定义数组。
    • 切片类型(Slice Types):对一个连续的内存块进行引用,可以看作是动态数组。切片类型提供了访问和操作数据的一种高效方式。
    • 元组类型(Tuple Types):一种将多个不同类型的值组合在一起的数据结构,用圆括号和逗号分隔的元素序列表示。元组可以包含不同类型的元素,例如整数、浮点数、布尔值、字符串等。
    • 结构体类型(Struct Types):一种自定义的数据类型,可以包含多个不同类型的字段。结构体可以通过定义来指定其字段和属性。
    • 枚举类型(Enum Types):表示一个可能取多个值的变量。在 Rust 中,枚举类型使用 enum 关键字定义,每个可能的取值都是一个不同的枚举成员。

结构体嵌套

一个结构体可以包含任意类型的字段,当然也包括结构体。

在以下这个例子中,Address 结构体包含了 street、city 和 state 三个字段,而 Person 结构体则包含了 name、age 和 address 三个字段,其中 address 字段的类型是 Address 结构体。

struct Address {  street: String,  city: String,  state: String,  
}  struct Person {  name: String,  age: u8,  address: Address,  
}

结构体方法

方法(method)是在结构体上定义的功能,可以访问结构体的字段并执行一些操作。使用关键字impl,结构体可以对应一个或多个impl代码块。

例1:结构体转换为字符串描述

struct Student {name:String,age:u32,school:String,major:String,grade:String,state:bool
}impl Student {  fn to_string(&self) -> String {  format!("Student {{ name: {}, age: {}, school: {}, major: {}, grade: {}, state: {} }}", self.name, self.age, self.school, self.major, self.grade, self.state)  }  
} fn main() {let school = String::from("东南大学");let major = String::from("土木工程学院");let s = Student{name:String::from("杨程"),age:22,school,major,grade:String::from("大三"),state:true};println!("{}", s.to_string());
}

输出:

Student { name: 杨程, age: 22, school: 东南大学, major: 土木工程学院, grade: 大三, state: true }

注意:上例中有一个rust结构体的特殊用法,使用同名变量在结构体外为对应字段赋值。

例2:矩形的周长和面积

struct Rectangle {  width: f32,  height: f32,  
}  impl Rectangle {  // 构造函数  fn new(width: f32, height: f32) -> Rectangle {  Rectangle { width, height }  }  // 计算矩形的面积  fn area(&self) -> f32 {  self.width * self.height  }  // 计算矩形的周长  fn perimeter(&self) -> f32 {  (self.width + self.height) * 2.0}  
}impl Rectangle {  // 判断矩形是否相等  fn is_equal(&self, other: &Rectangle) -> bool {  self.width == other.width && self.height == other.height  }  
}  fn main() {  let rect1 = Rectangle::new(5.0, 6.0);  let rect2 = Rectangle::new(5.0, 6.0);  println!("Rectangle 1 area: {}", rect1.area());  println!("Rectangle 1 perimeter: {}", rect1.perimeter());  println!("Rectangle 2 area: {}", rect2.area());  println!("Rectangle 2 perimeter: {}", rect2.perimeter());  if rect1.is_equal(&rect2) {  println!("Rectangles are equal");  } else {  println!("Rectangles are not equal");  }  
}

输出:

Rectangle 1 area: 30
Rectangle 1 perimeter: 22
Rectangle 2 area: 30
Rectangle 2 perimeter: 22
Rectangles are equal 

例3:结构体字段的更新与输出

struct Person {  name: String,  age: u32,  
}  impl Person {  // 这是构造函数,用于创建一个新的 Person 实例  fn new(name: String, age: u32) -> Person {  Person { name, age }  }  fn say_hello(&self) {  println!("Hello, my name is {} and I'm {}.", self.name, self.age);  }  fn update_age(&mut self, new_age: u32) {  self.age = new_age;  } fn update_name(&mut self, new_name: String) {  self.name = new_name;  }  
}  fn main() {  // 创建一个新的 Person 实例  let mut person = Person::new("Tom".to_string(), 5);  // 调用 say_hello 方法,输出 Person 的信息  person.say_hello();  // 调用 update_age 方法,更新 Person 的年龄  person.update_age(3);  // 再次调用 say_hello 方法,输出更新后的信息  person.say_hello(); person.update_age(5);person.update_name(String::from("Jerry"));  person.say_hello();  
}

输出:

Hello, my name is Tom and I'm 5.
Hello, my name is Tom and I'm 3.
Hello, my name is Jerry and I'm 5.

关联函数

之所以"结构体方法"不叫"结构体函数"是因为"函数"这个名字留给了这种函数:它在 impl 块中却没有 &self 参数。这种函数不依赖实例,但是使用它需要声明是在哪个 impl 块中的,比如上小节例2和例3中的构造函数new()就是关联函数,类似于字符串函数String::new(),String::from("Jerry")。

示例:

#[derive(Debug,Clone)]
struct Rectangle {width: u32,height: u32,
}impl Rectangle {fn create(width: u32, height: u32) -> Rectangle {Rectangle { width, height }}fn area(self) -> u32 {self.width * self.height}fn area2(&self) -> u32 {self.width * self.height}
}fn main() {let rect = Rectangle::create(30, 50);println!("{:?}", rect);println!("Area: {}", Rectangle::area(rect.clone()));println!("Area: {}", rect.area2());
}

输出:

Rectangle { width: 30, height: 50 }
Area: 1500
Area: 1500

结构体方法与关联函数的区别

参数传递方式的区别

结构体方法:结构体方法默认情况下是可变的(mutable),也就是说可以修改结构体的字段。在调用方法时,可以通过引用(&self)或可变引用(&mut self)来传递结构体实例,以便修改其字段。例如:my_struct.my_method(&mut my_struct)。

关联函数:关联函数默认情况下是不可变的(immutable),也就是说无法修改结构体的字段。在调用函数时,只能通过常量引用(&self)来传递结构体实例,因为常量引用是只读的。例如:let my_struct = MyStruct {...}; my_struct.my_function()。

使用方式的区别

结构体方法:结构体方法可以直接在结构体实例上调用,无需显式传递结构体实例。例如:my_struct.my_method()。

关联函数:关联函数需要显式传递结构体实例作为参数。例如:MyStruct::my_function(my_struct)。

结构体的trait

Rust 中的 trait 是一种抽象类型,用于定义泛型行为,trait 可以理解为一种接口。trait 使用关键字 derive 来自动生成实现。通过使用 derive,可以避免手动编写冗长的代码,提高代码的可读性和可维护性。trait 有很多,比如Copy,Clone,Debug,Default,Drop,Hash,Ord,PartialOrd,Send,Sync等等,先挑几种最常用的学一下:

#[derive(Debug)]

在 Rust 语言中用于自动生成一个结构体的 Debug 实现,Debug 是 Rust 标准库中的一个 trait,用于在控制台打印调试信息。

使用 #[derive(Debug)] 属性可以为结构体自动生成一个 Debug 实现,这样在需要打印调试信息时,就可以使用 {:?} 格式化字符串来打印该结构体的内容。例如,在上面的代码中,s 结构体的 Debug 实现已经被自动生成,因此可以使用 println!("{:?}", s) 来打印出结构体 s 的内容。

例1:

#[derive(Debug)]
struct Point {x: i32,y: i32,
}impl Point {fn distance(&self, other: &Point) -> f32 {let x_diff = self.x - other.x;let y_diff = self.y - other.y;((x_diff * x_diff + y_diff * y_diff) as f32).sqrt()}
}fn main() {let p1 = Point { x: 3, y: 0 };let p2 = Point { x: 0, y: 4 };println!("Distance between {:?} and {:?} is {}.", p1, p2, p1.distance(&p2));
}

输出:

Distance between Point { x: 3, y: 0 } and Point { x: 0, y: 4 } is 5. 

例2:

#[derive(Debug)]
struct Student {name: String,age: u32,school: String,major: String,grade: String,state: bool,
}  impl Student {fn new() -> Student {return Student {age: 0,name: String::new(),school: String::from(""),major: "".to_string(),grade: "".to_string(),state: false,};}
}fn main() {  let mut s = Student::new();s.name = String::from("杨程");s.age = 22;s.school = String::from("东南大学");s.major = String::from("土木工程学院");s.grade = String::from("大三");s.state = true;println!("{:?}", s);
}

输出:

Student { name: "杨程", age: 22, school: "东南大学", major: "土木工程学院", grade: "大三", state: true } 

与上一小节的例2对比,输出内容基本一致,就多了String的引号标记。相比自动生成 Debug 实现可以简化代码编写过程,并且可以避免手动实现 Debug 时可能出现的错误。

在本例中,使用宏打印结构体println!("{:?}", s);时,第一行的代码#[derive(Debug)]是必须的,如果去掉就会报错:

error[E0277]: `Student` doesn't implement `Debug`
  --> E:\.rs\struct2.rs:31:22
   |
31 |     println!("{:?}", s);
   |                      ^ `Student` cannot be formatted using `{:?}`
   |
   = help: the trait `Debug` is not implemented for `Student`
   = note: add `#[derive(Debug)]` to `Student` or manually `impl Debug for Student`
   = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider annotating `Student` with `#[derive(Debug)]`
   |
1  + #[derive(Debug)]
2  | struct Student {
   |

error: aborting due to previous error

自定义打印宏 

1. impl fmt::Debug for Student

返回值:fmt::Result; 调用:println!("{:?}", s);

use std::fmt;struct Student {name: String,age: u32,school: String,major: String,grade: String,state: bool,
}  impl fmt::Debug for Student {  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {write!(f,"Student {{ name: {}, age: {}, school: {}, major: {}, grade: {}, state: {} }}",self.name, self.age, self.school, self.major, self.grade, self.state)}  
}  fn main() {  let school = String::from("东南大学");let major = String::from("土木工程学院");let s = Student {name: String::from("杨程"),age: 22,school,major,grade: String::from("大三"),state: true,};  println!("{:?}", s);
}

输出:

Student { name: 杨程, age: 22, school: 东南大学, major: 土木工程学院, grade: 大三, state: true }  

2. impl fmt::Display for Student

返回值:fmt::Result; 调用:println!("{}", s); {}里不需要:?

use std::fmt;struct Point {x: i32,y: i32,
}impl fmt::Display for Point {fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {write!(f, "({}, {})", self.x, self.y)}
}impl Point {fn distance(&self, other: &Point) -> f32 {let x_diff = self.x - other.x;let y_diff = self.y - other.y;((x_diff * x_diff + y_diff * y_diff) as f32).sqrt()}
}fn main() {let p1 = Point { x: 3, y: 0 };let p2 = Point { x: 0, y: 4 };println!("Distance between {} and {} is {}.", p1, p2, p1.distance(&p2));
}

输出:

Distance between Point(3, 0) and Point(0, 4) is 5.

输出要与使用#[derive(Debug)]时一样,只要修改write宏的第2个参数,如:

impl fmt::Display for Point {fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {write!(f, "Point {{ x: {}, y: {} }}", self.x, self.y)}
}

#[derive(PartialEq)]

使用#[derive(PartialEq)]为结构体自动实现了PartialEq trait。这使得可以直接使用==运算符比较两个结构体实例的相等性。

例1:

#[derive(PartialEq)]
struct Point {  x: i32,  y: i32,  
}fn main() {let point1 = Point { x: 10, y: 20 };  let point2 = Point { x: 10, y: 20 };  if point1 == point2 {  println!("The two points are equal.");  } else {  println!("The two points are not equal.");  }
}

输出:

The two points are equal.

例2:

#[derive(Debug, PartialEq)]
struct Person {name: String,age: u32,
}fn main() {let person1 = Person {name: String::from("Alice"),age: 25,};let person2 = Person {name: String::from("Bob"),age: 30,};let person3 = Person {name: String::from("Alice"),age: 25,};println!("Is {:?} equal to {:?}? {}", person1, person2, person1 == person2);println!("Is {:?} equal to {:?}? {}", person1, person3, person1 == person3);
}

输出:

Is Person { name: "Alice", age: 25 } equal to Person { name: "Bob", age: 30 }? false
Is Person { name: "Alice", age: 25 } equal to Person { name: "Alice", age: 25 }? true

#[derive(Default)]

调用#[derive(Default)],相当于创建一个默认的结构体实例,每一个字段都是对应数据类型的默认值,无需手动为每个字段设置默认值。

例1:

#[derive(Default,Debug)]
struct Circle {radius: f32,
}  impl Circle {fn area(&self) -> f32 {let pi = std::f32::consts::PI;pi * self.radius * self.radius}
}fn main() {let mut c = Circle::default();println!("Circular area of {:?} = {}.", c, c.area());c.radius = 1.0;println!("Circular area of {:?} = {}.", c, c.area());
}

输出:

Circular area of Circle { radius: 0.0 } = 0.
Circular area of Circle { radius: 1.0 } = 3.1415927.

例2:

#[derive(Debug, Default)]
struct Student {  name: String,  age: u32,  school: String,  major: String,  grade: String,  state: bool,  
}  fn main() {  let mut s1 = Student::default(); println!("{:?}", s1);s1.name = String::from("杨程");  s1.age = 22;  s1.school = String::from("东南大学");  s1.major = String::from("土木工程学院");  s1.grade = String::from("大三");  s1.state = true;  println!("{:?}", s1);  let s2 = Student {  age: 23,  grade: String::from("大四"),  ..s1  //注意这里的结构体更新语法};  println!("{:?}", s2);  
}

输出:

Student { name: "", age: 0, school: "", major: "", grade: "", state: false }
Student { name: "杨程", age: 22, school: "东南大学", major: "土木工程学院", grade: "大三", state: true }
Student { name: "杨程", age: 23, school: "东南大学", major: "土木工程学院", grade: "大四", state: true }

此例还有一个rust结构体的特殊用法,当结构体大部分字段需要被设置成与现存的另一个结构体的一样,仅需更改其中的一两个字段的值,可以使用结构体更新语法,在现存的结构体名前加上两个连续的句号:“..Struct_Name”。

#[derive(Clone)]

Clone 在复制过程中对所有字段进行逐个复制,包括所有引用类型和原始类型。这意味着每次进行克隆时,都会创建新的数据副本。 

示例:

#[derive(Clone)]
struct Person {  name: String,  age: i32,  
}  fn main() {  let mut person1 = Person { name: String::new(), age: 0 };  let mut person2 = person1.clone();person1.name = "Alice".to_string();person1.age = 22;println!("Person 1: {}, {}", person1.name, person1.age);println!("Person 2: {}, {}", person2.name, person2.age);person2 = person1.clone();println!("Person 2: {}, {}", person2.name, person2.age);
}

输出:

Person 1: Alice, 22
Person 2: , 0
Person 2: Alice, 22

其他相关内容

模式匹配

结构体可用 模式匹配(Pattern Matching)来解构和访问其字段。

例1:

struct Point {x: i32,y: i32,
}fn main() {let p = Point { x: 10, y: 20 };match p {Point { x, y } => {println!("x:{}, y: {}", x, y);}}
}

例2:

struct Time {  hour: i32,  minute: i32,  second: i32,  
}  fn main() {  let t = Time { hour: 10, minute: 30, second: 45 };  match t {  Time { hour, minute, second } => {  print!("The time is {}:", hour);println!("{}:{}", minute, second);  }  }  
}

结构体大小

结构体的大小在C/C++中使用运算符 sizeof 来计算;在Rust语言中,则使用标准库中的一个模块std::mem::中的size_of和size_of_val,它提供了与内存管理相关的函数。

1. std::mem::size_of

用于计算给定类型的大小,不接受任何参数。这个函数返回一个给定类型的大小(以字节为单位)。它是一个泛型函数,可以用于任何类型。

示例:

#![allow(dead_code)]struct Point {x: i32,y: i32,
}  struct Person {name: String,age: i32,height: f32,is_employed: bool,
}  fn main() {let point = Point { x: 10, y: 20 };  println!("Size of Point: {}", std::mem::size_of::<Point>());let person = Person {name: "Hann Yang".to_string(),age: 50,height: 1.72,is_employed: true,};  println!("Size of Person: {}", std::mem::size_of::<Person>());
}

输出:

Size of Point: 8
Size of Person: 40 

2. std::mem::size_of_val

用于计算给定值的大小,接受一个值作为参数。它用于获取一个值的大小(以字节为单位)。与 size_of 函数不同的是,size_of_val 函数可以用于任何值,而非类型。

示例:

#![allow(dead_code)]struct Point {x: i32,y: i32,
}  struct Person {name: String,age: i32,height: f32,is_employed: bool,
}  fn main() {let point = Point { x: 10, y: 20 };  println!("Size of Point: {}", std::mem::size_of_val(&point));let person = Person {name: "Hann Yang".to_string(),age: 50,height: 1.72,is_employed: true,};  println!("Size of Person: {}", std::mem::size_of_val(&person));
}

输出:

Size of Point: 8
Size of Person: 40 

注意:在这两个例子中,计算类型大小和值大小的结果都是相同的,因为这里没有涉及到指针或其他复杂的情况。 


本文总结

结构体是Rust中一种重要的数据结构,用于组织不同类型的字段。以下是结构体的重点内容的总结:

  • 结构体定义:使用struct关键字来定义结构体,结构体可以包含多个字段,每个字段可以有不同的类型。
  • 结构体实例:定义一个结构体后,可以使用结构体名称来创建结构体实例,通过.运算符来访问结构体字段。
  • 结构体分类:结构体可以分为三种类型:单元结构体(())、元组结构体(用逗号分隔的多个字段)和具名结构体(有自定义名称的字段)。
  • 结构体嵌套:结构体可以嵌套,用于组织和存储复杂的数据。
  • 结构体方法:结构体可以定义方法,用于在结构体上执行操作。结构体方法与关联函数类似,但只能在结构体上调用。
  • 关联函数:通过impl关键字在结构体上定义关联函数,用于在结构体实例上执行特定操作。关联函数可以是普通函数或方法。
  • 自定义打印宏:使用derive(Debug)]来自动实现fmt::Debug trait,实现自定义的打印输出格式。
  • 其他相关内容:结构体可以通过derive属性来自动实现其他trait,如PartialEq(部分相等性)、Default(默认值)和Clone(克隆)。
  • 结构体大小:在Rust中,结构体的内存大小是固定的,可以在定义时指定大小,也可以使用#[repr(C)]来指定大小和布局。
  • 模式匹配:可以使用模式匹配来访问和匹配结构体的字段,这使得在编写代码时更加灵活和方便。

总的来说,结构体是Rust中非常强大和灵活的数据结构,可以用于组织和操作各种类型的数据。通过使用结构体、方法、关联函数和其他相关特性,可以轻松地实现复杂的数据结构和算法。

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

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

相关文章

【后端面经】前言汇总(0)

文章目录 一、机会是留给有准备的人二、课程设计第一部分:微服务架构第二部分:数据库与 MySQL第三部分:消息队列第四部分:缓存所谓缓存用得好,性能没烦恼。第五部分:NoSQL三、总结一、机会是留给有准备的人 近两年互联网行业增速放缓,ChatGPT 又引发了一波新的 AI 浪潮,…

使用ffmpeg合并视频遇到的坑

下面以Linux环境介绍为主 1.ffmpeg可执行命令不同的环境是不同的&#xff0c;Linux在执行命令前还需要授权。 2.合并视频命令&#xff1a; 主要命令: {} -f concat -auto_convert 0 -safe 0 -i {} -y -c:v copy 坑一&#xff1a;其中第一个花括号替换的是可执行命令所在的…

【GitOps系列】使用Kustomize和Helm定义应用配置

文章目录 使用 Kustomize 定义应用改造示例应用1.创建基准和多环境目录2.环境差异分析3.为 Base 目录创建通用 Manifest4.为开发环境目录创建差异 Manifest5.为预发布环境创建差异 Manifest6.为生产环境创建差异 Manifest 部署 Kustomize 应用部署到开发环境部署到生产环境 使用…

OpenCv (C++) 使用矩形 Rect 覆盖图像中某个区域

文章目录 1. 使用矩形将图像中某个区域置为黑色2. cv::Rect 类介绍 1. 使用矩形将图像中某个区域置为黑色 推荐参考博客&#xff1a;OpenCV实现将任意形状ROI区域置黑&#xff08;多边形区域置黑&#xff09; 比较常用的是使用 Rect 矩形实现该功能&#xff0c;代码如下&…

打造i-SMART智能网联平台,亚马逊云科技助力上汽快速出海

当前在各大外资车企不断加码在华投资之际&#xff0c;越来越多的中国汽车品牌纷纷开始走出国门&#xff0c;加速推进全球化业务&#xff0c;将赛道转至更为广阔的海外市场。 上汽海外出行科技有限公司&#xff08;简称“上汽海外出行”&#xff09;成立于2018年&#xff0c;承…

linux高并发web服务器开发(web服务器)18_函数解析http请求, 正则表达式,sscanf使用,http中数据特殊字符编码解码

pdf详情版 01 学习目标 编写函数解析http请求 ○ GET /hello.html HTTP/1.1\r\n ○ 将上述字符串分为三部分解析出来编写函数根据文件后缀&#xff0c;返回对应的文件类型sscanf - 读取格式化的字符串中的数据 ○ 使用正则表达式拆分 ○ [^ ]的用法通过浏览器请求目录数据 ○…

【unity之IMGUI实践】单例模式管理数据存储【二】

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;uni…

每日一题——迷宫问题(I)

迷宫问题——I 题目链接 思路 创建二维数组&#xff0c;并实现输入 首先输入二维数组的行和列&#xff1a; int n, m; scanf("%d%d", &n, &m);然后动态开辟二维数组&#xff1a; 注&#xff1a;对动态开辟还不太了解的同学可以看看&#x1f449;C语言—…

CPU密集型和IO密集型任务的权衡:如何找到最佳平衡点

关于作者&#xff1a;CSDN内容合伙人、技术专家&#xff0c; 从零开始做日活千万级APP。 专注于分享各领域原创系列文章 &#xff0c;擅长java后端、移动开发、人工智能等&#xff0c;希望大家多多支持。 目录 一、导读二、概览三、CPU密集型与IO密集型3.1、CPU密集型3.2、I/O密…

opencv-15 数字水印原理

最低有效位&#xff08;Least Significant Bit&#xff0c;LSB&#xff09;指的是一个二进制数中的第 0 位&#xff08;即最低位&#xff09;。 最低有效位信息隐藏指的是&#xff0c;将一个需要隐藏的二值图像信息嵌入载体图像的最低有效位&#xff0c;即将载体图像的最低有效…

再开源一款轻量内存池

前两天已开源线程池&#xff0c;开源一款轻量线程池项目&#xff0c;本节继续开源另一个孪生兄弟&#xff1a;内存池。 本节的线程池与内存池代码解析会在我的星球详细讲解。 内存池&#xff1a;https://github.com/Light-City/light-memory-pool 线程池&#xff1a;https://gi…

Python案例分析|使用Python图像处理库Pillow处理图像文件

本案例通过使用Python图像处理库Pillow&#xff0c;帮助大家进一步了解Python的基本概念&#xff1a;模块、对象、方法和函数的使用 使用Python语言解决实际问题时&#xff0c;往往需要使用由第三方开发的开源Python软件库。 本案例使用图像处理库Pillow中的模块、对象来处理…

ZooKeeper原理剖析

1.ZooKeeper简介 ZooKeeper是一个分布式、高可用性的协调服务。在大数据产品中主要提供两个功能&#xff1a; 帮助系统避免单点故障&#xff0c;建立可靠的应用程序。提供分布式协作服务和维护配置信息。 2.ZooKeeper结构 ZooKeeper集群中的节点分为三种角色&#xff1a;Le…

git如何撤销commit(未push)

文章目录 前言undo commitreset current branch to here Undo Commit&#xff0c;Revert Commit&#xff0c;Drop Commit的区别 是否删除对代码的修改是否删除Commit记录是否会新增Commit记录Undo Commit不会未Push会&#xff0c;已Push不会不会Revert Commit会不会会Drop Com…

vue 3.0 如何加载图片

.logo { background: url(~/assets/images/logo.svg) no-repeat center center/contain; width: 117px; height: 24px; margin: 0 20px; } <a class"logo" href"#"></a> 比较实用的书写方式

汽车销售数据可视化分析实战

1、任务 市场需求&#xff1a;各年度汽车总销量及环比&#xff0c;各车类、级别车辆销量及环比 消费能力/价位认知&#xff1a;车辆销售规模及环比、不同价位车销量及环比 企业/品牌竞争&#xff1a;各车系、厂商、品牌车销量及环比&#xff0c;市占率及变化趋势 热销车型&…

python多线程排查

问题 公司服务总是莫名其妙的cpu饱满排查了代码中的定时任务&#xff0c;排除之后仍经常出现类似问题。是时候debug了 排查过程 cpu劣化是一个过程&#xff0c;cpu持续增长到60%&#xff0c;然后突然服务雪崩不服务了。排查下来看sleep的物理线程和cpu增长的幅度一致 那么…

hadoop安全保护机制(kerberos + ldap)

信息安全理论&#xff1a; CIA模型&#xff1a;机密性、完整性和可用性 CIA模型能够帮助建议一些信息安全原则&#xff0c;但该模型并不是一个需要严格遵守的规则 hadoop平台可能设计多个CIA模型组件&#xff0c;也kennel一个也不涉及 机密性&#xff1a; 信息只应该被期望的…

探索AI图像安全,助力可信AI发展

探索AI图像安全&#xff0c;助力可信AI发展 0. 前言1. 人工智能发展与安全挑战1.1 人工智能及其发展1.2 人工智能安全挑战 2. WAIC 2023 多模态基础大模型的可信 AI2.1 WAIC 2023 专题论坛2.2 走进合合信息 3. AI 图像安全3.1 图像篡改检测3.2 生成式图像鉴别3.3 OCR 对抗攻击技…

Vis相关的期刊会议

中国计算机学会推荐国际学术会议和期刊目录 文档&#xff0c; 下载 link&#xff1a;CCF推荐国际学术刊物目录-中国计算机学会 一.可视化方向文章 1.IEEE VIS&#xff0c;是由 IEEE Visualization and Graphics Technical Committee(VGTC) 主办的数据可视化领域的顶级会议&a…