Rust 程序设计语言学习——常见集合:Vector String Map

news2024/9/19 16:48:32

Rust 中常见的集合包括 Vector(列表)、String(字符串)和 Map(键值对)。

在这里插入图片描述

Vec<T>,也被称为 vector。vector 允许我们在一个单独的数据结构中储存多于一个的值,它在内存中彼此相邻地排列所有的值。vector 只能储存相同类型的值。

String 字符串类型由 Rust 标准库提供,而不是编入核心语言,它是一种可增长、可变、可拥有和 UTF-8 编码的字符串类型。当 Rustaceans 提及 Rust 中的 "字符串 "时,他们可能指的是 String 或 string slice &str 类型,而不仅仅是其中一种类型。

介绍 Map 我们主要来学习哈希 map(hash map)。HashMap<K, V> 类型储存了一个键类型 K 对应一个值类型 V 的映射。它通过一个哈希函数来实现映射,决定如何将键和值放入内存中。

一、Vector

1.1 新建 vector

创建一个空的 vector 可以使用 Vec::new 函数。

let v: Vec<i32> = Vec::new();

注意这里我们增加了一个类型注解,vector 是用泛型实现的。因为没有向这个 vector 中插入任何值,Rust 并不知道我们想要储存什么类型的元素。

通常,我们会用初始值来创建一个 Vec<T> 而 Rust 会推断出储存值的类型。为了方便 Rust 提供了 vec! 宏,这个宏会根据我们提供的值来创建一个新的 vector。

let v = vec![1, 2, 3];

因为我们提供了 i32 类型的初始值,Rust 可以推断出 v 的类型是 Vec<i32>

1.2 更新 vector

对于新建一个 vector 并向其增加元素,可以使用 push 方法。

    let mut v: Vec<i32> = Vec::new();

    v.push(1);
    v.push(2);
    v.push(3);
    v.push(4);
    v.push(5);

如果想要能够改变它的值,必须使用 mut 关键字使其可变。放入其中的所有值都是 i32 类型的,而且 Rust 也根据数据做出如此判断,所以可以不需要 Vec<i32> 注解。

1.3 读取 vector 的元素

有两种方法引用 vector 中储存的值:通过索引或使用 get 方法。

fn main() {
    let mut v: Vec<i32> = Vec::new();

    v.push(1);
    v.push(2);
    v.push(3);
    v.push(4);
    v.push(5);

    let index = 3;

    let val = &v[index];
    println!("The element is {val}");

    let val: Option<&i32> = v.get(index);
    match val {
        Some(val) => println!("The element is {val}"),
        None => println!("Element not found."),
    }
}

当使用索引作为参数调用 get 方法时,会得到一个可以用于 matchOption<&T>

运行结果:

The element is 4
The element is 4

越界访问 vector

调整代码 index 改为 10。

fn main() {
    let mut v: Vec<i32> = Vec::new();

    v.push(1);
    v.push(2);
    v.push(3);
    v.push(4);
    v.push(5);

    let index = 10;

    let val: Option<&i32> = v.get(index);
    match val {
        Some(val) => println!("The element is {val}"),
        None => println!("Element not found."),
    }

    let val = &v[index];
    println!("The element is {val}");
}

get 方法被传递了一个数组外的索引时,它不会 panic 而是返回 None。所以正常打印出了“Element not found.”。对于 [] 方法,当引用一个不存在的元素时 Rust 会造成 panic(thread ‘main’ panicked at src/main.rs:18:17:)。

运行结果:

    Exited with status 101

    ---------------------------------Standard Error---------------------------------

       Compiling playground v0.0.1 (/playground)
        Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.39s
         Running `target/debug/playground`
    thread 'main' panicked at src/main.rs:18:17:
    index out of bounds: the len is 5 but the index is 10
    note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

    ---------------------------------Standard Output---------------------------------

    Element not found.

vector 借用规则

一旦程序获取了一个有效的引用,借用检查器将会执行所有权和借用规则来确保 vector 内容的这个引用和任何其他引用保持有效。当我们获取了 vector 的第一个元素的不可变引用并尝试在 vector 末尾增加一个元素的时候,如果尝试在函数的后面引用这个元素是行不通的。

fn main() {
    let mut v: Vec<i32> = Vec::new();

    v.push(1);
    v.push(2);
    v.push(3);
    v.push(4);
    v.push(5);

    let first = &v[0];

    v.push(6);

    println!("The first element is: {first}");
}

运行结果:

    Compiling playground v0.0.1 (/playground)
    error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable
      --> src/main.rs:12:5
       |
    10 |     let first = &v[0];
       |                  - immutable borrow occurs here
    11 |
    12 |     v.push(6);
       |     ^^^^^^^^^ mutable borrow occurs here
    13 |
    14 |     println!("The first element is: {first}");
       |                                     ------- immutable borrow later used here

    For more information about this error, try `rustc --explain E0502`.
    error: could not compile `playground` (bin "playground") due to 1 previous error

为什么第一个元素的引用会关心 vector 结尾的变化?不能这么做的原因是由于 vector 的工作方式:在 vector 的结尾增加新元素时,在没有足够空间将所有元素依次相邻存放的情况下,可能会要求分配新内存并将老的元素拷贝到新的空间中。这时,第一个元素的引用就指向了被释放的内存。借用规则阻止程序陷入这种状况。

1.4 遍历 vector 中的元素

如果想要依次访问 vector 中的每一个元素,我们可以遍历其所有的元素而无需通过索引一次一个的访问。

fn main() {
    let v = vec![1, 2, 3, 4, 5];

    for element in &v {
        println!("{element}");
    }
}

运行结果:

1
2
3
4
5

我们也可以遍历可变 vector 的每一个元素的可变引用以便能改变它们。

fn main() {
    let mut v = vec![1, 2, 3, 4, 5];

    for element in &mut v {
        *element += 10;
    }

    for element in &v {
        println!("{element}");
    }
}

运行结果:

11
12
13
14
15

二、String

字符串就是作为字节的集合外加一些方法实现的,当这些字节被解释为文本时,这些方法提供了实用的功能。

2.1 新建字符串

很多 Vec 可用的操作在 String 中同样可用,事实上 String 被实现为一个带有一些额外保证、限制和功能的字节 vector 的封装。

创建一个空的字符串可以使用 String::new 函数。

let mut s = String::new();

通常字符串会有初始数据,因为我们希望一开始就有这个字符串。为此,可以使用 to_string 方法,它能用于任何实现了 Display trait 的类型,比如字符串字面值。

fn main() {
    let s = "初始值";
    println!("{s}");
    let str = s.to_string();
    println!("{str}");
    // 该方法也可直接用于字符串字面值:
    let str1 = "初始值".to_string();
    println!("{str1}");
}

运行结果:

初始值
初始值
初始值

也可以使用 String::from 函数来从字符串字面值创建 String。

 let s = String::from("初始值");

2.2 更新字符串

String 的大小可以增加,其内容也可以改变。另外,可以方便的使用 + 运算符或 format! 宏来拼接 String 值。

push_str

push_str 方法采用字符串 slice。

fn main() {
    let mut s = String::from("初始值");
    s.push_str(" 附加部分");
    println!("{s}");
    let str = " 继续追加所有权未转移";
    s.push_str(str);
    println!("{s}");
    println!("使用 str,其值为:{str}");
}

如果 push_str 方法获取了 str 的所有权,就不能在最后一行(println!("使用 str,其值为:{str}");)打印出其值了。

运行结果:

初始值 附加部分
初始值 附加部分 继续追加所有权未转移
使用 str,其值为: 继续追加所有权未转移

push

push 方法被定义为获取一个单独的字符作为参数,并附加到 String 中。

let mut s = String::from("hell");
s.push('o');

执行以上代码之后,s 将会包含 “hello”。

使用 + 运算符或 format! 宏拼接字符串

通常我们会希望将两个已知的字符串合并在一起。一种办法是使用 + 运算符;另一种是使用 format! 宏,format! 与 println! 的工作原理相同,不过不同于将输出打印到屏幕上,它返回一个带有结果内容的 String。

另外,宏 format! 生成的代码使用引用所以不会获取任何参数的所有权。

fn main() {
    let s1 = String::from("Tom ");
    let s2 = String::from("Peter ");
    let s3 = String::from("Joy ");

    let s = format!("{s1}-{s2}-{s3}");
    println!("final str(format!):{s}");
    println!("s1:{s1}");

    let s = s1 + "-" + &s2 + "-" + &s3;
    println!("final str(+):{s}");
    //println!("s1:{s1}");//error[E0382]: borrow of moved value: `s1`
}

打开注释的最后一行会报错。s1 在相加(使用 + 号)后不再有效的原因,与使用 + 运算符时调用的函数签名有关。所以虽然 let s = s1 + "-" + &s2 + "-" + &s3; 看起来就像它会复制字符串并创建一个新的字符串,而实际上这个语句会获取 s1 的所有权,附加上从 s2、s3 中拷贝的内容,并返回结果的所有权。

运行结果:

final str(format!):Tom -Peter -Joy 
s1:Tom 
final str(+):Tom -Peter -Joy 

2.3 索引字符串

在很多语言中,通过索引来引用字符串中的单独字符是有效且常见的操作。然而在 Rust 中,如果你尝试使用索引语法访问 String 的一部分,会出现一个错误。Rust 的字符串不支持索引。

最后一个 Rust 不允许使用索引获取 String 字符的原因是,索引操作预期总是需要常数时间(O(1))。但是对于 String 不可能保证这样的性能,因为 Rust 必须从开头到索引位置遍历来确定有多少有效的字符。

2.4 字符串 slice

为了更明确索引并表明你需要一个字符串 slice,相比使用 [] 和单个值的索引,可以使用 [] 和一个 range 来创建含特定字节的字符串 slice。

fn main() {
    let hello = "Здравствуйте";

    let s = &hello[0..8];
    println!("s:{s}");
}

这里,s 会是一个 &str,它包含字符串的前八个字节。

运行结果:

s:Здра

如果获取 &hello[0..1] 会发生什么呢?Rust 在运行时会 panic,就跟访问 vector 中的无效索引时一样:

Compiling playground v0.0.1 (/playground)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.42s
     Running `target/debug/playground`
thread 'main' panicked at src/main.rs:4:19:
byte index 1 is not a char boundary; it is inside 'З' (bytes 0..2) of `Здравствуйте`
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

2.5 遍历字符串

操作字符串每一部分的最好的方法是明确表示需要字符还是字节。对于单独的 Unicode 标量值使用 chars 方法。对 “Зд” 调用 chars 方法会将其分开并返回两个 char 类型的值。

fn main() {
    for c in "Здравствуйте".chars() {
        println!("{c}");
    }

    for b in "Здравствуйте".bytes() {
        println!("{b}");
    }
}

运行结果

З
д
р
а
в
с
т
в
у
й
т
е
208
151
208
180
209
128
208
176
208
178
209
129
209
130
208
178
209
131
208
185
209
130
208
181

有效的 Unicode 标量值可能会由不止一个字节组成。

三、Map

Map 是一种键值对结构,我们主要来学习哈希 Map。哈希 map(hash map)。HashMap<K, V> 类型储存了一个键类型 K 对应一个值类型 V 的映射。它通过一个哈希函数(hashing function)来实现映射,决定如何将键和值放入内存中。

3.1 新建哈希 map

可以使用 new 创建一个空的 HashMap,并使用 insert 增加元素。

use std::collections::HashMap;

fn main() {
    let mut employees = HashMap::new();

    employees.insert(10000, String::from("Tom"));
    employees.insert(10002, String::from("Peter"));

    for (key, value) in &employees {
        println!("{key}:{value}");
    }
}

运行结果

10000:Tom
10002:Peter

注意必须首先 use 标准库中集合部分的 HashMap。标准库中对 HashMap 的支持也相对较少,例如,并没有内建的构建宏。

vector 一样,哈希 map 将它们的数据储存在堆上,这个 HashMap 的键类型是 i32,值类型是 String。类似于 vector,哈希 map 是同质的:所有的键必须是相同类型,值也必须都是相同类型。

3.2 访问哈希 map 中的值

可以通过 get 方法并提供对应的键来从哈希 map 中获取值。get 方法返回 Option<&V>,如果某个键在哈希 map 中没有对应的值,get 会返回 None。可以使用与 vector 类似的方式来遍历哈希 map 中的每一个键值对,也就是 for 循环。

use std::collections::HashMap;

fn main() {
    let mut employees = HashMap::new();

    employees.insert(10000, String::from("Tom"));
    employees.insert(10002, String::from("Peter"));

    let employee_number = 10003;
    let opt_name = employees.get(&employee_number);
    match opt_name {
        Some(name) => println!("{employee_number}:{name}"),
        None => println!("There is no such number!"),
    }

    for (key, value) in &employees {
        println!("{key}:{value}");
    }
}

运行结果

There is no such number!
10002:Peter
10000:Tom

3.3 哈希 map 和所有权

对于像 i32 这样的实现了 Copy trait 的类型,其值可以拷贝进哈希 map。对于像 String 这样拥有所有权的值,其值将被移动而哈希 map 会成为这些值的所有者。如果将值的引用插入哈希 map,这些值本身将不会被移动进哈希 map。但是这些引用指向的值必须至少在哈希 map 有效时也是有效的。

use std::collections::HashMap;

fn main() {
    let mut employees = HashMap::new();

    let employee_number = 10003;
    let employee_name = String::from("Tom");

    employees.insert(employee_number, employee_name);

    println!("{employee_number}");
    println!("{employee_name}");
}

编译报错:

   Compiling playground v0.0.1 (/playground)
error[E0382]: borrow of moved value: `employee_name`
  --> src/main.rs:12:15
   |
7  |     let employee_name = String::from("Tom");
   |         ------------- move occurs because `employee_name` has type `String`, which does not implement the `Copy` trait
8  |
9  |     employees.insert(employee_number, employee_name);
   |                                       ------------- value moved here
...
12 |     println!("{employee_name}");
   |               ^^^^^^^^^^^^^^^ value borrowed here after move
   |
   = 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 cloning the value if the performance cost is acceptable
   |
9  |     employees.insert(employee_number, employee_name.clone());
   |                                                    ++++++++

For more information about this error, try `rustc --explain E0382`.
error: could not compile `playground` (bin "playground") due to 1 previous error

报错信息提示我们:借用被移动的值:“employee_name”。

3.4 更新哈希 map

当我们想要改变哈希 map 中的数据时,必须决定如何处理一个键已经有值了的情况。可以选择完全无视旧值并用新值代替旧值。可以选择保留旧值而忽略新值,并只在键 没有 对应值时增加新值。或者可以结合新旧两值。

覆盖一个值

如果我们插入了一个键值对,接着用相同的键插入一个不同的值,与这个键相关联的旧值将被替换。

use std::collections::HashMap;

fn main() {
    let mut employees = HashMap::new();

    employees.insert(10003, String::from("Tom"));
    employees.insert(10003, String::from("Peter"));

    println!("{:?}", employees);
}

运行结果

{10003: "Peter"}

只在键没有对应值时插入键值对

我们经常会检查某个特定的键是否已经存在于哈希 map 中并进行如下操作:如果哈希 map 中键已经存在则不做任何操作。如果不存在则连同值一块插入。

为此哈希 map 有一个特有的 API,叫做 entry,它获取我们想要检查的键作为参数。entry 函数的返回值是一个枚举,Entry,它代表了可能存在也可能不存在的值。Entryor_insert 方法在键对应的值存在时就返回这个值的可变引用,如果不存在则将参数作为新值插入并返回新值的可变引用。

use std::collections::HashMap;

fn main() {
    let mut employees = HashMap::new();

    employees.insert(10003, String::from("Tom"));

    employees.entry(10003).or_insert(String::from("Peter"));
    employees.entry(10002).or_insert(String::from("Peter"));

    println!("{:?}", employees);
}

运行结果

{10002: "Peter", 10003: "Tom"}

根据旧值更新一个值

另一个常见的哈希 map 的应用场景是找到一个键对应的值并根据旧的值更新它。or_insert 方法返回键对应值的一个可变引用(&mut V)。

use std::collections::HashMap;

fn main() {
    let text = "Hello world hello world test";
    let mut map = HashMap::new();

    for word in text.split_whitespace() {
        let word_count = map.entry(word).or_insert(0);
        *word_count += 1;
    }

    println!("{:?}", map);
}

运行结果

{"hello": 1, "Hello": 1, "world": 2, "test": 1}

split_whitespace 方法返回一个由空格分隔 text 值子 slice 的迭代器。or_insert 方法返回这个键的值的一个可变引用(&mut V)。这里我们将这个可变引用储存在 word_count 变量中,所以为了赋值必须首先使用星号(*)解引用 word_count。这个可变引用在 for 循环的结尾离开作用域,这样所有这些改变都是安全的并符合借用规则。

参考链接

  1. Rust 官方网站:https://www.rust-lang.org/zh-CN
  2. Rust 官方文档:https://doc.rust-lang.org/
  3. Rust Play:https://play.rust-lang.org/
  4. 《Rust 程序设计语言》

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

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

相关文章

Java之Writer类:探索Java中的输出流

哈喽&#xff0c;各位小伙伴们&#xff0c;你们好呀&#xff0c;我是喵手。运营社区&#xff1a;C站/掘金/腾讯云&#xff1b;欢迎大家常来逛逛 今天我要给大家分享一些自己日常学习到的一些知识点&#xff0c;并以文字的形式跟大家一起交流&#xff0c;互相学习&#xff0c;一…

拿捏数据结构-top_k问题

top_k问题时间复杂度的计算 这里提前说明&#xff0c;时间复杂度的计算的目的是来计算向上调整的更优还是向下调整更优&#xff0c;从肉眼看的话向下调整优于向上调整&#xff0c;接下来我们进行时间复杂度的计算。 此时我们会用到等比数列求和以及裂项相消 如图 首先我们假设求…

【物联网实战项目】STM32C8T6+esp8266/mqtt+dht11+onenet+uniapp

一、实物图 前端uniapp效果图&#xff08;实现与onenet同步更新数据&#xff09; 首先要确定接线图和接线顺序&#xff1a; 1、stm32c8t6开发板连接stlinkv2下载线 ST-LINK V2STM323.3V3.3VSWDIOSWIOSWCLKSWCLKGNDGND 2、ch340串口连接底座&#xff08;注意RXD和TXD的连接方式…

Spring Boot集成shiro之使用redis缓存demo

1.背景 上次发了这篇文章《Spring Boot集成Shiro快速入门Demo》后&#xff0c;有网友“just.blue”后台反馈集成redis有点问题&#xff0c;今天特地把集成过程发出来 2.为什么要使用cache 用来减轻数据库的访问压力&#xff0c;从而提升查询效率。 3.Shiro使用Redis做缓存 …

Go 实现 WebSocket 的双向通信

在Go语言中实现WebSocket的双向通信通常需要使用第三方库&#xff0c;其中 gorilla/websocket 是一个非常流行和广泛使用的库。 1、安装 go get github.com/gorilla/websocket 2、编写WebSocket服务器代码 package mainimport ("fmt""github.com/gorilla/we…

AlibabaCloud(阿里云)支付方式介绍,使用虚拟卡支付阿里云

一、支付方式 二、 添加支付方式 点击添加支付方式按钮&#xff0c;您将进入添加支付方式流程。选择您偏好的支付方式&#xff0c;按页面指导进行添加即可。 1、信用卡 可以使用Fomepay的信用进行支付&#xff0c;点击获取 依次输入您银行卡的卡号、有效期、安全码&#xff…

实现一个简单的 Google Chrome 扩展程序

目录 &#x1f9ed; 效果展示 # 图示效果 a. 拓展程序列表图示效果&#xff1a; b. 当前选项卡页面右键效果&#xff1a; c. 拓展程序消息提示效果&#xff1a; &#x1f4c7; 项目目录结构 # 说明 # 结构 # 文件一览 ✍ 核心代码 # manifest.json # background.j…

JWT-登录后下发令牌

后端 写一个jwt工具类&#xff0c;处理令牌的生成和校验&#xff0c;如&#xff1a; 响应数据样例&#xff1a; 前端要做的&#xff1a;

Nginx文件解析漏洞复现:CVE-2013-4547

漏洞原理 CVE-2013-4547漏洞是由于非法字符空格和截止符导致Nginx在解析URL时的有限状态机混乱&#xff0c;导致攻击者可以通过一个非编码空格绕过后缀名限制。假设服务器中存在文件1. jpg&#xff0c;则可以通过改包访问让服务器认为访问的为PHP文件。 漏洞复现 开启靶场 …

均值算法详细教程(个人总结版)

背景 均值算法&#xff0c;也称为平均值算法&#xff0c;是统计分析中的基本方法之一。它通过求取一组数据的平均值来概括数据的集中趋势。在数据分析、机器学习、信号处理等领域&#xff0c;均值算法被广泛应用。 均值的种类 算术均值&#xff08;Arithmetic Mean&#xff…

手把手教你快速玩转香橙派AIPro

什么是香橙AIPro&#xff1f; OrangePi AIpro(8T)采用昇腾AI技术路线&#xff0c;具体为4核64位处理器AI处理器&#xff0c;集成图形处理器&#xff0c;支持8TOPS AI算力&#xff0c;拥有8GB/16GB LPDDR4X&#xff0c;可以外接32GB/64GB/128GB/256GB eMMC模块&#xff0c;支持…

设计模式 19 模板模式 Template Pattern

设计模式 19 模板模式 Template Pattern 1.定义 模板模式&#xff08;Template Pattern&#xff09;是一种行为设计模式&#xff0c;它定义了一个算法的骨架&#xff0c;将一些步骤的具体实现延迟到子类中。在模板模式中&#xff0c;定义了一个抽象类&#xff0c;其中包含了一个…

2024.5组队学习——MetaGPT(0.8.1)智能体理论与实战(中):订阅智能体OSS实现

传送门&#xff1a; 《2024.5组队学习——MetaGPT&#xff08;0.8.1&#xff09;智能体理论与实战&#xff08;上&#xff09;&#xff1a;MetaGPT安装、单智能体开发》《2024.5组队学习——MetaGPT&#xff08;0.8.1&#xff09;智能体理论与实战&#xff08;下&#xff09;&…

2024年电工杯高校数学建模竞赛(A题) 建模解析| 园区微电网风光储协调优化配置

问题重述及方法概述 问题1&#xff1a;各园区独立运营储能配置方案及其经济性分析 经济性分析采用成本-效益分析方法&#xff0c;计算购电量、弃风弃光电量、总供电成本和单位电量平均供电成本等指标。 问题2&#xff1a;联合园区储能配置方案及其经济性分析 经济性分析采用成…

《Ai企业知识库》-rasa X安装使用

背景&#xff1a; Rasa X 是一个为构建、改进和管理对话式AI助手而设计的工具。它是Rasa开源机器学习框架的一个扩展&#xff0c;旨在实现“对话驱动开发”&#xff08;Conversation-Driven Development&#xff09;。Rasa X 主要特点包括&#xff1a; 交互式学习&#xff1a;…

百度智能小程序源码系统 关键词推广优化排名高 带完整的安装代码包以及搭建教程

系统概述 百度智能小程序源码系统是一套完整的解决方案&#xff0c;为用户提供了创建、发布和管理智能小程序的平台。它基于百度平台的先进技术&#xff0c;确保小程序在运行和展示方面具有出色的表现。 代码示例 系统特色功能 1.关键词推广优化&#xff1a;系统内置了强大的…

Day 40 Web容器-Tomcat

Tomcat 一&#xff1a;Tomcat简介 1.简介 ​ Tomcat是Apache软件基金会&#xff08;Apache Software Foundation&#xff09;的Jakarta 项目中的一个核心项目 ​ Tomcat服务器是一个免费的开放源代码的Web应用服务器&#xff0c;属于轻量级应用服务器 ​ Tomcat是WEB容器/WE…

JVM(内存区域划分、类加载机制、垃圾回收机制)

目录 一. 内存区域划分 1.本地方法栈(Native Method Stacks) 2.虚拟机栈(JVM Stacks) 3.程序计数器(Program Counter Register) 4.堆(Heap) 5.元数据区(Metaspace) 二.类加载机制 1.加载 2.验证 3.准备 4.解析 5.初始化 "双亲委派模型" 三. GC 垃圾回收…

[自动驾驶技术]-7 Tesla自动驾驶方案之算法(AI Day 2022)

特斯拉在2022年AI Day上更新了感知规控算法模型&#xff0c;核心引入了Occupancy技术。下图是特斯拉活动日展示的主题内容&#xff0c;本文主要解读Planning和Neural Network部分。 1 规划决策 Interaction search-交互搜索 特斯拉在自动驾驶规划中使用了一种高度复杂和优化的…

SpringCloud整合Seata1.5.2

Windows下部署Seata1.5.2可参照博文&#xff1a;Windows下部署Seata1.5.2&#xff0c;解决Seata无法启动问题-CSDN博客 1. 引入依赖 <!-- 分布式事务 --> <dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-st…