rust容器

2023-09-18 21:54:20

标准库提供了常见的容器。包括向量 ( Vector )、映射( HashMap )、集合( HashSet )。

一、向量Vector

数组有一个缺点,就是它的长度在编译时就确定了,一旦确定就永不可更改。
向量是一个长度可变的数组。向量的存储在堆上,因此长度可变。

Rust在标准库中定义了结构体Vec用于表示向量。

(一)定义向量
一维向量
1.new()创建一个空向量
语法格式

let mut instance_name: Vec<T> = Vec::new();
例子
let v1: Vec<i32> = Vec::new(); // 创建类型为i32的空向量

2.vec!()宏创建向量
这种方式的创建方法类似于数组的语法。
它也有3种创建方式。
(1)创建空向量。需要指定类型。

let mut vec_marco: Vec<i32> = vec![];

(2)指定所有元素。可以省略类型。

let mut vec_marco = vec![1, 2, 3, 4, 5];

(3)指定初始值和长度。可以省略类型。

let mut vec_marco = vec![0; 5];     // 长度为5,元素初始化为0

注意,长度可以是变量,这点与数组不同。
例子

let len = 10;
let zero_vec = vec![0; len];

3.从数组创建向量

let arr = [1, 2, 3, 4, 5];
let v = arr.to_vec();

二维向量
1.使用new()创建空向量。需要指定类型。

let mut instance_name: Vec<Vec<T>> = Vec::new();
例子
let v1: Vec<Vec<i32>> = Vec::new();

2.使用vec!()宏创建向量
(1)创建空向量。需要指定类型。

let mut vec_marco: Vec<Vec<i32>> = vec![];

(2)指定所有元素。可以省略类型。

let mut vec_marco = vec![vec![1, 2, 3, 4, 5], ...];

(3)指定初始值和长度。可以省略类型。

let mut vec_marco = vec![vec![0; 5]; 10];
例子
let width = 4;
let height = 4;
let mut array = vec![vec![0; width]; height];

3.从二维数组创建二维向量
例如

let s = [
[0, 0, 1, 0, 0],
[0, 0, 1, 0, 0],
[0, 0, 1, 0, 0],
[0, 0, 1, 0, 0],
];
let s: Vec<_> = s.iter().map(|&e| e.to_vec()).collect();

(二)使用向量
1.获取长度
len()方法
例子

fn main() {
    let v = vec![1, 2, 3];
    println!("{}", v.len());
    let width = 4;
    let height = 4;
    let array = vec![vec![0; width]; height];
    println!("{} {}", array.len(), array[0].len());
}
运行结果如下
3
4 4

2.添加元素
使用push方法来追加单个元素
实例

fn main() {
    let mut vector = vec![1, 2, 4, 8];
    vector.push(16);
    vector.push(32);
    vector.push(64);
    println!("{:?}", vector);
    let mut arr: Vec<Vec<i32>> = Vec::new();
    arr.push(Vec::new());
    arr.push(vec![]);
    arr[0].push(1);
    println!("{:?}", arr);
}
运行结果:
[1, 2, 4, 8, 16, 32, 64]
[[1], []]

使用append方法用于将一个向量拼接到另一个向量的尾部
实例

fn main() {
    let mut v1: Vec<i32> = vec![1, 2, 4, 8];
    let mut v2: Vec<i32> = vec![16, 32, 64];
    v1.append(&mut v2);
    println!("{:?}", v1);
}
运行结果:
[1, 2, 4, 8, 16, 32, 64]

2.删除元素
使用remove()删除元素
remove() 方法移除并返回向量中指定的下标索引处的元素,将其后面的所有元素移到向左移动一位。

fn main() {
    let mut v = vec![10,20,30];
    v.remove(1);
    println!("{:?}",v);
}
运行结果如下
[10, 30]

clear
删除所有元素

let mut v = vec![10,20,30];
v.clear();
println!("{:?}",v);

3.获取元素
因为向量实现了Deref Target=[T],所以向量自动实现了切片的所有方法。
(1)使用get方法
get方法根据索引返回对元素或子切片的引用。
如果给定位置,则返回该位置上的元素的引用,如果越界则返回None。
如果给定范围,则返回对应于该范围的子切片,如果越界则返回None。
例子

let v = vec![10, 40, 30];
assert_eq!(Some(&40), v.get(1));
assert_eq!(Some(&[10, 40][..]), v.get(0..2));
assert_eq!(None, v.get(3));
assert_eq!(None, v.get(0..4));

(2)get_mut
get_mut方法根据索引返回对元素或子切片的可变引用
如果给定位置,则返回该位置上的元素的可变引用,如果越界则返回None。
如果给定范围,则返回对应于该范围的可变子切片,如果越界则返回None。
例子

let mut x = vec![0, 1, 2];
if let Some(elem) = x.get_mut(1) {
    *elem = 42;
}
assert_eq!(x, &[0, 42, 2]);

(3)使用[]
实例

fn main() {
    let v = vec![1, 2, 4, 8];
    println!("{}", v[1]);
}
运行结果:
2

二维向量

array[2][2] = 5;
println!("{:?}", array);

例子

use std::io;
fn main(){
    let width = 4;
    let height = 4;
    let mut array = vec![vec![0; width]; height];
    for i in 0..4 {
         let mut buf = String::from("");
         io::stdin().read_line(&mut buf).unwrap();
         array[i] = buf.split_whitespace().map(|s| s.parse().unwrap()).collect();
    }
    println!("{:?}", array);
}

4.遍历向量
(1)使用索引

fn main() {
    let v = vec![100, 32, 57];
    for i in 0..v.len() {
            println!("{}", v[i]);
    }
}

(2)使用向量的引用
实例

fn main() {
    let v = vec![100, 32, 57];
    for i in &v {
            println!("{}", i);
    }
}
运行结果:
100
32
57

实例

fn main() {
    let mut v = vec![100, 32, 57];
    for i in &mut v {
        *i += 50;
    }
    println!("{:?}", v);
}

(3)使用迭代器
iter()返回一个只读迭代器

for num in nums1.iter() {
     print!("{} ", num);
}
println!();

iter_mut()返回一个可写迭代器

let mut nums1 = [1; 5];
let mut i = 0;
for num in nums1.iter_mut() {
     *num = i;
     i += 1;
}
println!("{:?}", nums1);

into_iter()返回一个迭代器,但是转让所有权

let mut nums1 = [1; 5];
for num in nums1.into_iter() {
    print!("{} ", num);
}
println!();

for num in nums1.into_iter()
实际上等价于
for num in nums1

(4)使用迭代器的enumerate

let mut nums1 = [1; 5];
for (pos, v) in nums1.iter().enumerate() {
    println!("nums[{}]={}", pos, v);
}
println!("{:?}", nums1);
for (pos, v) in nums1.iter_mut().enumerate() {
    *v=pos;
    println!("nums[{}]={}", pos, v);
}
println!("{:?}", nums1);

二维向量
(1)使用索引

let mut v = vec![vec![1, 2, 3, 4, 5], vec![3, 9, 8]];
for i in 0..v.len() {
    for j in 0..v[i].len() {
         println!("{}", v[i][j]);
    }
}

(2)使用引用
例子

let s = [
[0, 0, 1, 0, 0],
[0, 0, 1, 0, 0],
[0, 0, 1, 0, 0],
[0, 0, 1, 0, 0],
];
let mut s: Vec<_> = s.iter().map(|&e| e.to_vec()).collect();
for row in &s{
    for col in row{
         print!("{} ", col);
    }
    println!();
}
for row in &mut s {
    for col in row {
         *col += 1;
         print!("{} ", col);
    }
    println!();
}

(3)使用向量的迭代器

let mut grid = [[0; 5]; 5];
for row in grid.iter() {
    for col in row.iter() {
         print!("{} ", col);
    }
    println!();
}
let mut i = 0;
for row in grid.iter_mut(){
    for col in row.iter_mut() {
         *col = i;
         i += 1;
         print!("{} ", col);
    }
    println!();
}

(4)使用迭代器的enumerate

let mut grid = [[0; 5]; 5];
for (i, row) in grid.iter().enumerate() {
    for (j, col) in row.iter().enumerate() {
         print!("{}", col);
    }
    println!()
}
for (i, row) in grid.iter_mut().enumerate() {
    for (j, col) in row.iter_mut().enumerate() {
         *col = 1;
    }
}

6.使用contains() 判断向量是否包含某个元素
如果值在向量中存在则返回 true ,否则返回 false 。

fn main() {
     let v = vec![10,20,30];
     if v.contains(&10) {
         println!("found 10");
     }
     println!("{:?}",v);
}
运行结果如下
found 10
[10, 20, 30]

7.逆转向量

reverse
适当地反转切片中元素的顺序。
例子
let mut v = [1, 2, 3];
v.reverse();
assert!(v == [3, 2, 1]);

二、映射HashMap

映射表(Map)在其他语言中广泛存在。其中应用最普遍的就是散列映射表(Hash Map)。
HashMap就是 键值对 的集合。映射表中不允许有重复的键,但允许不同的键有相同的值。

Rust语言定义了HashMap结构体来表示映射表。
HashMap结构体定义在std::collections模块中,使用之前需要导入std::collections模块。

(一)定义映射表
1.使用new创建空映射表
语法格式如下

let mut instance_name: HashMap<type1, type2> = HashMap::new();

实例

use std::collections::HashMap;
let mut map: HashMap<&str, i32> = HashMap::new();
let mut map = HashMap::new();//可以省略类型

2.可以从数组初始化HashMap
例子

use std::collections::HashMap;
let solar_distance = HashMap::from([
("Mercury", 0.4),
("Venus", 0.7),
("Earth", 1.0),
("Mars", 1.5),
]);

(二)使用映射表
1.使用len()获取键值对的个数
例子

use std::collections::HashMap;
fn main() {
     let mut stateCodes = HashMap::new();
     stateCodes.insert("name","简单教程");
     stateCodes.insert("site","https://www.twle.cn");
     println!("size of map is {}",stateCodes.len());
}
编译运行结果如下
size of map is 2

2.添加键值对
使用insert()方法用于插入或更新一个键值对
如果键已经存在,则更新为新的值,并则返回旧的值。
如果键不存在则执行插入操作并返回None 。

例子

fn main() {
    let mut map = HashMap::new();
    map.insert("color", "red");
    map.insert("size", "10 m^2");
    println!("{}", map.get("color").unwrap());
}
运行结果:
red

3.删除指定键值对
remove()用于从映射表中删除指定的键值对。
如果键值对存在则返回删除的键值对,返回的数据格式为 (&'a K, &'a V) 。
如果键值对不存在则返回None

例子

use std::collections::HashMap;
fn main() {
     let mut stateCodes = HashMap::new();
     stateCodes.insert("name","简单教程");
     stateCodes.insert("site","https://www.twle.cn");
     stateCodes.insert("slogn","简单教程,简单编程");
     println!("length of the hashmap {}",stateCodes.len());
     stateCodes.remove(&"site");
     println!("length of the hashmap after remove() {}",stateCodes.len());
}
编译运行结果如下
length of the hashmap 3
length of the hashmap after remove() 2

clear
清除map,删除所有键值对。
例子

use std::collections::HashMap;
let mut a = HashMap::new();
a.insert(1, "a");
a.clear();
assert!(a.is_empty());

4.根据键获取相应的值
使用get()方法获取键相应的值。
如果值不存在,则返回None 。
如果值存在,则返回值的一个引用。

例子

use std::collections::HashMap;
fn main() {
     let mut stateCodes = HashMap::new();
     stateCodes.insert("name","简单教程");
     stateCodes.insert("site","https://www.twle.cn");
     println!("size of map is {}",stateCodes.len());
     println!("{:?}",stateCodes);
     match stateCodes.get(&"name") {
         Some(value)=> {
             println!("Value for key name is {}",value);
          }
          None => {
              println!("nothing found");
          }
     }
}
编译运行结果如下
size of map is 2
{"name": "简单教程", "site": "https://www.twle.cn"}
Value for key name is简单教程

get_mut
实例

use std::collections::HashMap;
fn main() {
    let mut map = HashMap::new();
    map.insert(1, "a");
    if let Some(x) = map.get_mut(&1) {
        *x = "b";
    }
}

get_key_value
例子

use std::collections::HashMap;
let mut map = HashMap::new();
map.insert(1, "a");
assert_eq!(map.get_key_value(&1), Some((&1, &"a")));
assert_eq!(map.get_key_value(&2), None);

5.遍历映射表
(1)使用引用

for (book, review) in &book_reviews {
     println!("{book}: \"{review}\"");
}

for (book, review) in &mut book_reviews {
    *review = 0;
     println!("{book}: \"{review}\"");
}

(2)使用迭代器
iter()方法会返回映射表中 键值对的引用组成的无序迭代器。
迭代器元素的类型为 (&'a K, &'a V) 。
实例

use std::collections::HashMap;
fn main() {
    let mut map = HashMap::new();
    map.insert("color", "red");
    map.insert("size", "10 m^2");
    for p in map.iter() {
        println!("{:?}", p);
    }
}
运行结果:
("color", "red")
("size", "10 m^2")
迭代元素是表示键值对的元组。

iter_mut
例子

use std::collections::HashMap;
let mut map = HashMap::from([
("a", 1),
("b", 2),
("c", 3),
]);
// 更新所有值
for (_, val) in map.iter_mut() {
     *val *= 2;
}

6.是否包含指定的键
contains_key()方法用于判断映射表中是否包含指定的键值对。
如果包含指定的键,那么会返回相应的值的引用,否则返回None 。

例子

use std::collections::HashMap;
fn main() {
     let mut stateCodes = HashMap::new();
     stateCodes.insert("name","简单教程");
     stateCodes.insert("site","https://www.twle.cn");
     stateCodes.insert("slogn","简单教程,简单编程");
     if stateCodes.contains_key(&"name") {
         println!("found key");
     }
}
编译运行结果如下
found key

7.entry
entry方法返回键值对
例子

use std::collections::HashMap;
let mut player_stats = HashMap::new();
fn random_stat_buff() -> u32 {
     42
}
player_stats.entry("health").or_insert(100);     // 没有就插入,有就跳过
player_stats.entry("defence").or_insert_with(random_stat_buff);     //没有就插入,有就跳过
let stat = player_stats.entry("attack").or_insert(100);     //没有就插入,返回值的引用
*stat += random_stat_buff();
player_stats.entry("mana").and_modify(|mana| *mana += 200).or_insert(100);     // 有就加200,没有就插入100
println!("{:?}", player_stats);

9.自定义键类型
派生Eq和Hash。 我们还必须导出PartialEq。
例子

use std::collections::HashMap;
#[derive(Hash, Eq, PartialEq, Debug)]
struct Viking {
     name: String,
     country: String,
}
impl Viking {
     /// 创建一个新的Viking。
     fn new(name: &str, country: &str) -> Viking {
         Viking { name: name.to_string(), country: country.to_string() }
     }
}
// 使用HashMap存储Viking的健康点。
let vikings = HashMap::from([
(Viking::new("Einar", "Norway"), 25),
(Viking::new("Olaf", "Denmark"), 24),
(Viking::new("Harald", "Iceland"), 12),
]);
// 使用派生的实现来打印Viking的状态。
for (viking, health) in &vikings {
     println!("{viking:?} has {health} hp");
}

10.其他
keys
返回一个迭代器,以任意顺序访问所有键。 迭代器元素类型为 &'a K。
例子

use std::collections::HashMap;
let map = HashMap::from([
("a", 1),
("b", 2),
("c", 3),
]);
for key in map.keys() {
     println!("{key}");
}

values
返回一个以任意顺序访问所有值的迭代器。 迭代器元素类型为 &'a V。
例子

use std::collections::HashMap;
let map = HashMap::from([
("a", 1),
("b", 2),
("c", 3),
]);
for val in map.values() {
     println!("{val}");
}

is_empty
如果map不包含任何元素,则返回true。
例子

use std::collections::HashMap;
let mut a = HashMap::new();
assert!(a.is_empty());
a.insert(1, "a");
assert!(!a.is_empty());

三、集合HashSet

HashSet是没有重复值的相同数据类型的值的集合。
Rust语言标准库std::collections中定义了结构体HashSet用于描述集合。

(一)定义集合
1.new()创建一个空集合
语法格式如下

let mut hash_set_name = HashSet::new();

2.可以从数组初始化HashSet:

use std::collections::HashSet;
let viking_names = HashSet::from(["Einar", "Olaf", "Harald"]);

(二)使用集合
1.获取集合的长度len()
len() 方法用于获取集合的长度,也就是集合中元素的个数。

范例

use std::collections::HashSet;
fn main() {
     let mut languages = HashSet::new();
     languages.insert("Python");
     languages.insert("Rust");
     languages.insert("Ruby");
     languages.insert("PHP");
     println!("size of the set is {}",languages.len());
}
编译运行结果如下
size of the set is 4

2.添加元素
insert() 用于插入一个值到集合中,如果集合中已经存在指定的值,则返回 false ,否则返回 true 。

例子

use std::collections::HashSet;
fn main() {
     let mut languages = HashSet::new();
     languages.insert("Python");
     languages.insert("Rust");
     languages.insert("Ruby");
     languages.insert("PHP");
     languages.insert("Rust"); // 插入失败但不会引发异常
     println!("{:?}",languages);
}
编译运行结果如下
{"Python", "PHP", "Rust", "Ruby"}

3.删除集合元素
remove() 方法用于从集合中删除指定的值。
删除之前如果值 value 存在于集合中则返回 true ,如果不存在则返回 false 。

例子

use std::collections::HashSet;
fn main() {
     let mut languages = HashSet::new();
     languages.insert("Python");
     languages.insert("Rust");
     languages.insert("Ruby");
     println!("length of the Hashset: {}",languages.len());
     languages.remove(&"Kannan");
     println!("length of the Hashset after remove() : {}",languages.len());
}
编译运行结果如下
length of the Hashset: 3
length of the Hashset after remove() : 3

clear
删除所有值。
例子

use std::collections::HashSet;
let mut v = HashSet::new();
v.insert(1);
v.clear();
assert!(v.is_empty());

4.获取元素
get() 方法用于获取集合中指定值的一个引用。
如果值 value 存在于集合中则返回集合中的相应值的一个引用,否则返回 None 。

例子

use std::collections::HashSet;
fn main() {
     let mut languages = HashSet::new();
     languages.insert("Python");
     languages.insert("Rust");
     languages.insert("Ruby");
     languages.insert("PHP");
     match languages.get(&"Rust"){
         Some(value)=>{
              println!("found {}",value);
          }
          None =>{
              println!("not found");
          }
     }
     println!("{:?}",languages);
}
编译运行结果如下
found Rust
{"Python", "Ruby", "PHP", "Rust"}

take
删除并返回集合中等于给定值的值 (如果有)。
该值可以是集合值类型的任何借用形式,但是借用形式上的Hash和Eq必须与值类型的那些匹配。
例子

use std::collections::HashSet;
let mut set = HashSet::from([1, 2, 3]);
assert_eq!(set.take(&2), Some(2));
assert_eq!(set.take(&2), None);

5.遍历集合
(1)使用引用

for book in &books {
     println!("{book}");
}

(2)使用迭代器
iter()方法用于返回集合中所有元素组成的无序迭代器。
迭代器元素的顺序是无序的,毫无规则的。而且每次调用iter() 返回的元素顺序都可能不一样。

例子

use std::collections::HashSet;
fn main() {
     let mut languages = HashSet::new();
     languages.insert("Python");
     languages.insert("Rust");
     languages.insert("Ruby");
     languages.insert("PHP");
     for language in languages.iter() {
         println!("{}",language);
     }
}
编译运行结果如下
PHP
Python
Rust
Ruby

6.判断集合是否包含某个值
contains() 方法用于判断集合是否包含指定的值。
如果值 value 存在于集合中则返回 true ,否则返回 false 。

例子

use std::collections::HashSet;
fn main() {
     let mut languages = HashSet::new();
     languages.insert("Python");
     languages.insert("Rust");
     languages.insert("Ruby");
     if languages.contains(&"Rust") {
         println!("found language");
     }
}
编译运行结果如下
found language

7.自定义类型
派生Eq和Hash。我们还必须导出PartialEq,这将在Eq中隐含在future中。

use std::collections::HashSet;
#[derive(Hash, Eq, PartialEq, Debug)]
struct Viking {
     name: String,
     power: usize,
}
let mut vikings = HashSet::new();
vikings.insert(Viking { name: "Einar".to_string(), power: 9 });
vikings.insert(Viking { name: "Einar".to_string(), power: 9 });
vikings.insert(Viking { name: "Olaf".to_string(), power: 4 });
vikings.insert(Viking { name: "Harald".to_string(), power: 8 });
for x in &vikings {
     println!("{x:?}");
}

8.其他
is_empty
如果集合不包含任何元素,则返回true。
例子

use std::collections::HashSet;
let mut v = HashSet::new();
assert!(v.is_empty());
v.insert(1);
assert!(!v.is_empty());

union
访问表示并集的值,即self或other中的所有值,没有重复项。
例子

use std::collections::HashSet;
let a = HashSet::from([1, 2, 3]);
let b = HashSet::from([4, 2, 3, 4]);
// 以任意顺序打印1、2、3、4。
for x in a.union(&b) {
println!("{x}");
}
let union: HashSet<_> = a.union(&b).collect();
assert_eq!(union, [1, 2, 3, 4].iter().collect());

intersection
访问表示相交的值,即self和other中的值。
当self和other中存在相等的元素时,生成的Intersection可能会引用其中一个。 如果T包含未通过其Eq实现进行比较的字段,并且可能在两组T的两个相等副本之间保持不同的值,则这可能是相关的。
例子

use std::collections::HashSet;
let a = HashSet::from([1, 2, 3]);
let b = HashSet::from([4, 2, 3, 4]);
// 以任意顺序打印2,3。
for x in a.intersection(&b) {
println!("{x}");
}
let intersection: HashSet<_> = a.intersection(&b).collect();
assert_eq!(intersection, [2, 3].iter().collect());

is_subset
如果集合是另一个集合的子集,则返回true,即other至少包含self中的所有值。
例子

use std::collections::HashSet;
let sup = HashSet::from([1, 2, 3]);
let mut set = HashSet::new();
assert_eq!(set.is_subset(&sup), true);
set.insert(2);
assert_eq!(set.is_subset(&sup), true);
set.insert(4);
assert_eq!(set.is_subset(&sup), false);

is_superset
如果集合是另一个集合的超集,则返回true,即self至少包含other中的所有值。
例子

use std::collections::HashSet;
let sub = HashSet::from([1, 2]);
let mut set = HashSet::new();
assert_eq!(set.is_superset(&sub), false);
set.insert(0);
set.insert(1);
assert_eq!(set.is_superset(&sub), false);
set.insert(2);
assert_eq!(set.is_superset(&sub), true);
更多推荐

在JavaScript中,什么是柯里化(currying)?

聚沙成塔·每天进步一点点⭐专栏简介⭐柯里化(Currying)⭐写在最后⭐专栏简介前端入门之旅:探索Web开发的奇妙世界欢迎来到前端入门之旅!感兴趣的可以订阅本专栏哦!这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发者,这里都将为你提供一个系统而又亲切的学习

html播放视频

文章目录<embed>标签<object>标签<video>标签<video>浏览器支持视频格式与浏览器的支持DOM元素提供的方法、属性和事件自定义控制栏<embed>标签<embed>标签的作用是在HTML页面中嵌入多媒体元素。前提:浏览器支持Flash。iPad和iPhone不能显示Flash视频。视频不能转成其他

【ES6知识】 Reflect 与 Proxy

文章目录前言一、Proxy代理对象1.1基本应用1.2同一个拦截器函数,可以设置拦截多个操作:1.3Proxy支持的拦截操作一览,一共13种:二、Reflect对象2.1基本使用2.2`Reflect`对象一共有13个静态方法三、使用Proxy实现观察者模式前言Proxy与Reflect是ES6为了操作对象引入的API

源码编译Qt 5.15.9+msvc2019

官方文档里给出了详细步骤:BuildingQtSourcesBuildingQt5fromGit(Wiki)注:本文基于windows11+vs2019x64+qt5.15.9,不编译QtWebEngine归纳总结如下:准备阶段QtforWindows-Requirements安装python,我这里用的是anacon

如何在Vue中引入video.js,并如何监听相关事件,禁止拖拽

如何在Vue中引入video.js,并如何监听相关事件最近考虑做一个视频播放网站,所以接触video.js会多一些,之前考虑到使用Vue-video-player来实现相关功能,结果发现当前技术已不再支持Flash播放器,无奈采用videojs,官方文档链接奉上Video.js1.Vue使用Video.jsa.引入vi

PDF文件的页眉页脚无法删除的原因和三种替代方法

大家好!今天六分职场为大家介绍一个PDF的常用操作。有的时候我们需要为PDF文件添加页眉页脚,但如果我们这个PDF文档是从其他地方参考的,经常会发现无法直接编辑或者删除PDF文件中页眉页脚。不用担心,我们使用WPS的PDF软件,有两种替代的方法可以删除PDF的页眉页脚,然后插入自己的页眉页脚。一、PDF页眉页脚无法删除

Windows系统部署WebDAV服务结合内网穿透实现公网访问,轻松共享文件与资源

windows搭建WebDAV服务,并内网穿透公网访问【无公网IP】文章目录windows搭建WebDAV服务,并内网穿透公网访问【无公网IP】1.安装IIS必要WebDav组件2.客户端测试3.cpolar内网穿透3.1打开Web-UI管理界面3.2创建隧道3.3查看在线隧道列表3.4浏览器访问测试4.安装Raidr

分布式事物【XA强一致性分布式事务实战、分布式架构的理论知识、TCC核心组成】(六)-全面详解(学习总结---从入门到深化)

目录XA强一致性分布式事务实战_业务层实现分布式架构的理论知识_BASE理论BASE理论三要素分布式事务解决方案_最终一致性分布式事务最终一致性分布式事务解决方案_TCC是什么TCC核心组成Hmily实现TCC分布式事务实战_认识Hmily-TCCHmily实现TCC分布式事务实战_业务场景介绍XA强一致性分布式事务实

leetcode题目分析(一)leetcode155最小栈

一、前言本题基于leetcode155最小栈这道题,说一下通过java解决的一些方法。需要尤其注意的是,此题输入的值的区间范围在-2^31<=val<=2^31-1.这将会影响我们最后一种最优解的结果出现问题。这些都是后话。二、解决思路其实在一开始的提交记录,我的方案忽略了题干中的常数时间,而是使用了偏向于工程的,将栈

经典指标策略回测一览

编辑经典指标策略回测一览关键词A股市场(沪深京三市)5000+股票20年内日线走势回测,区分除权,前复权,后复权三种模式;由于数据量较大,采用两种方式共享数据,一是天启网站的数据表格可视化,而是phpadmin数据管理台查看(自行SQL查询),登录方式在最下方。1、天启平台登录网站地址天启量化交易平台http://ma

redisplusplus笔记

设计点在redis层使用函数作为模板类型参数,也就是command层定义的函数。template<typenameCmd,typename...Args>autoRedis::command(Cmdcmd,Args&&...args)->typenamestd::enable_if<!std::is_convertib

热文推荐