내 연락처 정보
우편메소피아@프로톤메일.com
2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
여러분, 안녕하세요
오늘 2024년 자율주행 OS 개발훈련캠프 - 초등캠프 4단계 - 튜토리얼을 마쳤습니다.
Day2 바스락거리는 소리로 Rust 언어 연습하기 - 이동 의미론
https://doc.rust-lang.org/stable/book/ch04-00-이해-소유권.html
코드를 제출하면 권한이 없다는 메시지가 나타납니다. 어떻게 나가나요?
행동
참조 개발 환경 구성
https://rcore-os.cn/arceos-tutorial-book/ch01-02.html
내 주제
https://github.com/cicvedu/rustlings-학기-4-감시점
SSH를 통해 github 코드를 복제하려면 SSH 키를 만듭니다. Linux 환경에서는 ssh-keygen -t rsa -b 4096 -C "your Mailbox" 명령을 사용하여 SSH 키를 생성합니다. 다음 옵션을 모두 보려면 Enter 키를 누르기만 하면 됩니다. 그런 다음 cat ~/.ssh/id_rsa.pub를 사용하십시오.
Rust에는 컴파일러에 직접 구현되는 몇 가지 기본 유형이 있습니다. 이 섹션에서는 가장 중요한 유형을 살펴보겠습니다.
슬라이스 유형 슬라이스를 사용하면 컬렉션 전체가 아닌 컬렉션 내의 연속된 요소 시퀀스를 참조할 수 있습니다.
슬라이스는 일종의 참조이므로 소유권이 없습니다.
Rust에서 슬라이스는 배열이나 다른 슬라이스에서 연속된 요소의 시퀀스를 참조하는 뷰입니다. 슬라이스를 생성하려면 슬라이스의 시작 및 끝 위치를 지정해야 합니다(끝 위치의 인덱스는 포함되지 않음).배열로a
당신이 얻고 싶다면[2, 3, 4]
이 조각의 경우 인덱스 1에서 시작하여 인덱스 4(인덱스 4 제외)에서 끝나야 합니다.
테스트 코드를 수정하는 방법은 다음과 같습니다.
#[test]
fn slice_out_of_array() {
let a = [1, 2, 3, 4, 5];
// 从索引 1 开始,到索引 4 结束的切片
let nice_slice = &a[1..4];
assert_eq!([2, 3, 4], nice_slice);
}
이 예에서는&a[1..4]
다음에서 배열을 만들었습니다.a
슬라이스는 인덱스 1에서 시작하고 인덱스 3에서 끝나는데, Rust의 슬라이싱 구문은 왼쪽이 닫히고 오른쪽이 열리는 간격(시작은 포함하지만 끝은 포함하지 않음)이기 때문입니다.그래서nice_slice
배열이 포함되어 있습니다.a
가운데[2, 3, 4]
。
코드 편집의 루프 실험을 시작하려면 명령줄에 Rustlings watch를 입력하세요.
소유권 이해
소유권은 Rust의 가장 독특한 특징이며, 나머지 언어에 깊은 영향을 미칩니다.
이를 통해 Rust는 가비지 콜렉터가 필요 없이 메모리 안전을 보장할 수 있습니다.
소유권이란 무엇인가?
소유권 규칙 먼저 소유권 규칙을 살펴보겠습니다. 규칙을 설명하는 예를 살펴보면서 다음 규칙을 염두에 두십시오.
코드 샘플 자체는 정확하며 Rust의 소유권과 복사 개념을 보여줍니다. 그러나 코드가 컴파일 및 실행되는지 확인하고 가능한 몇 가지 개선 사항이나 수정 사항을 해결하려는 경우 다음과 같은 몇 가지 제안 사항이 있습니다.
확실하게 하다 takes_ownership
그리고makes_copy
기능하다main
이전에 정의된 함수왜냐하면 Rust의 함수는 먼저 선언한 다음 사용해야 하기 때문입니다.
메모 추가, 이유를 설명해라 s
존재하다takes_ownership
호출된 후에는 사용할 수 없으며,x
존재하다makes_copy
호출된 후에도 계속 사용할 수 있습니다.
다음에 추가 main
함수 반환 유형, 간단한 프로그램에서는 이것이 필요하지 않지만 좋은 프로그래밍 습관입니다.
Rust의 서식 도구 사용하기,예를 들어 rustfmt
, 코드를 깨끗하게 유지합니다.
위의 제안을 기반으로 수정된 코드는 다음과 같습니다.
fn takes_ownership(some_string: String) { // 函数定义在 main 之前
println!("{}", some_string);
} // some_string 的作用域结束,调用 Drop
fn makes_copy(some_integer: i32) { // 函数定义在 main 之前
println!("{}", some_integer);
} // some_integer 的作用域结束,没有调用 Drop,因为 i32 是 Copy 类型
fn main() -> () { // 明确 main 函数的返回类型为 ()
let s = String::from("hello"); // s 拥有 "hello" 的所有权
takes_ownership(s); // s 的值移动到 takes_ownership 函数
// 下面的代码尝试使用 s 将会导致编译错误,因为 s 的值已经移动
// let len = s.len(); // 错误:s 已移动
let x = 5; // x 包含值 5
makes_copy(x); // x 的值被复制到 makes_copy 函数
// x 仍然有效,因为 i32 是 Copy 类型
// x 仍然可以使用
println!("x is {}", x);
}
이번 개정판에서는 다음을 추가했습니다. main
함수 반환 유형()
,이것은 의미합니다 main
이 함수는 값을 반환하지 않습니다.또한 이유를 설명하는 설명이 추가됩니다.s
존재하다takes_ownership
호출된 후에는 사용할 수 없으며,x
존재하다makes_copy
전화 후에도 여전히 유효합니다.또한 다음과 같은 시도를 보여줍니다.takes_ownership
전화 후 이용s
컴파일 오류를 일으킬 수 있는 예x
존재하다makes_copy
호출 후에도 계속 사용할 수 있는 예입니다.
벡터는 가장 많이 사용되는 Rust 데이터 구조 중 하나입니다.
다른 프로그래밍 언어에서는 이를 단순히 배열이라고 부르지만 Rust는 조금 더 낮은 수준에서 동작하기 때문에 Rust의 배열은 스택에 저장됩니다(즉, 커지거나 작아질 수 없으며 컴파일 시점에 크기를 알아야 함). 반면 Vector는 힙에 저장됩니다(이러한 제한은 적용되지 않음).
벡터는 책의 후반부에 나오는 챕터지만, 우리는 벡터가 충분히 유용하다고 생각해서 조금 더 일찍 이야기할 겁니다. 다른 유용한 데이터 구조인 해시 맵에 대해서는 나중에 이야기하겠습니다.
vec_map
기능은 다음을 수락하는 것입니다.Vec<i32>
유형(즉, 32비트 정수를 포함하는 벡터)을 입력한 다음 새 값을 반환합니다.Vec<i32>
, 이 새 벡터의 각 요소는 원래 벡터의 해당 요소 크기의 두 배입니다.
구체적으로,vec_map
기능상map
그리고collect
이 방법은 다음과 같이 작동합니다.
**v.iter()
**: 이 메서드는 순회하는 반복자를 생성합니다. v
벡터의 각 요소.iter
메서드에서 반환된 반복자는 벡터의 요소에 대한 변경 불가능한 참조를 제공합니다.
**.map(|element| { element * 2 })
**:map
이 메소드는 클로저(익명 함수)를 허용합니다. 이 경우 클로저는 하나의 매개변수를 허용합니다.element
(벡터의 요소에 대한 불변 참조)는 이 요소의 값에 2를 곱한 값을 반환합니다.클로저 내부 작업element * 2
실제로 참조가 가리키는 데이터를 역참조하고 있습니다.*
연산자) 곱셈 연산을 수행합니다.
**.collect()
**:map
이 메서드는 클로저의 작업을 하나씩 적용하지만 결과를 즉시 수집하지 않는 지연 반복자를 반환합니다.collect
이를 전달하기 위해 메소드가 호출됩니다.map
처리된 요소는 새로운 요소로 수집됩니다.Vec<i32>
벡터에서.
사용 map
그리고collect
이점은 컬렉션의 각 요소에 대해 선언적 방식으로 작업을 수행하고 명시적인 루프를 작성할 필요 없이 결과를 새 컬렉션에 수집할 수 있다는 것입니다. 이렇게 하면 코드가 Rust 스타일과 더 간결해지고 일관성이 높아집니다.
사용방법은 이렇습니다 vec_map
기능 예:
fn main() {
let original_vec = vec![1, 2, 3, 4];
let doubled_vec = vec_map(&original_vec);
println!("{:?}", doubled_vec); // 这将打印:[2, 4, 6, 8]
}
이 예에서는vec_map
인수하다original_vec
참조, 새 벡터 생성doubled_vec
, 원본 벡터의 각 요소 값의 두 배를 포함하고 이를 인쇄합니다.
이러한 연습은 다음에서 적용되었습니다. 피엔크펠릭스'에스 Rust 튜토리얼 -- 펠릭스 씨, 고맙습니다!!!
이 섹션에서는 책 링크가 특히 중요합니다.
Rust에는 변경 가능한 참조에 대한 규칙이 있습니다. 언제든지 불변 참조를 얼마든지 가질 수 있거나 최대 하나의 변경 가능한 참조를 가질 수 있습니다. 이 규칙은 메모리 안전을 보장하고 데이터 경합을 방지합니다.
제공된 코드에 문제가 있습니다.main
함수가 두 개의 변경 가능한 참조를 생성하려고 시도했습니다.y
그리고z
, 둘 다 동일한 변수를 가리킵니다. x
. 이는 Rust의 차용 규칙이 동일한 범위의 동일한 변수에 대한 여러 변경 가능한 참조를 허용하지 않기 때문에 허용되지 않습니다. 이것이 코드가 컴파일되지 않는 이유입니다.
이 문제를 해결하려면 주어진 시간에 변경 가능한 참조가 하나만 존재하는지 확인해야 합니다. 고정된 코드는 다음과 같습니다.
fn main() {
let mut x = 100;
{
let y = &mut x;
*y += 100; // 此时 x 的值变为 200
} // 'y' 的作用域结束,可变引用被销毁
{
let z = &mut x; // 可以创建新的可变引用,因为 'y' 已经不存在了
*z += 1000; // 此时 x 的值变为 1200
} // 'z' 的作用域结束,可变引用被销毁
assert_eq!(x, 1200); // 断言 x 的值是 1200,这是正确的
}
이 수정 버전에서는 내부 범위를 생성하여 언제든지 하나의 변경 가능한 참조만 존재하도록 보장합니다.먼저, 우리는 만들었습니다.y
범위에 대해 작업이 수행된 다음 이 범위가 종료됩니다.y
더이상 유효하지 않은.그 후 우리는 만들었습니다.z
범위, 다시x
작업을 수행합니다. 이는 Rust의 차용 규칙을 따르므로 코드가 예상대로 컴파일되고 실행됩니다.
이 컴파일 오류 메시지는 Rust 코드의 수명 주기 문제를 나타냅니다.문제는string_uppercase
함수 구현 시 참조에 임시 값을 할당하려고 시도하는데 이는 허용되지 않습니다.
잘못된 코드 줄은 다음과 같습니다.
data = &data.to_uppercase();
이 코드 줄에서는data.to_uppercase()
생성됨String
새로운 인스턴스data
빌린.그러나 이 임시 값에 대한 참조를 다음에 할당해 보십시오.data
임시 값은 명령문 끝에서 즉시 삭제되므로 불법입니다.data
임시 값보다 긴 수명이 필요합니다.
이 문제를 해결하려면 수정해야 합니다. string_uppercase
변경 가능한 참조를 허용하고 참조가 가리키는 데이터에서 직접 호출되는 함수make_uppercase()
재할당을 시도하는 대신 방법을 사용하세요. 고정된 코드는 다음과 같습니다.
fn string_uppercase(data: &mut String) {
data.make_uppercase(); // 直接在 data 上调用 make_uppercase 方法
println!("{}", data);
}
이 수정 버전에서는 다음을 제거했습니다. mut data: &String
가운데mut
,왜냐하면 data
이미 변경 가능한 참조입니다.그럼 우리가 직접data
전화하다make_uppercase()
이므로 임시 값에는 문제가 없습니다.make_uppercase()
방식이 수정됩니다data
참조는 다음을 가리킨다.String
새 인스턴스를 만들지 않고 인스턴스String
。
또한,main
변경 가능한 참조를 전달하려면 함수 내 호출도 이에 따라 업데이트되어야 합니다.
fn main() {
let mut data = "Rust is great!".to_string();
string_uppercase(&mut data); // 传递一个可变引用
println!("{}", data); // 打印修改后的字符串
}
지금,string_uppercase
함수는 받아들인다data
변경 가능한 참조를 직접 수정하고main
기능상data
변경 가능하며 가능합니다.string_uppercase
수정되었습니다. 이렇게 하면 코드가 예상대로 컴파일되고 작동합니다.
/**
【昵称】小王同学
【坐标】山东
【自我介绍】
1. 高级后端工程师,擅长c++并发编程。
2. 专注分布式存储,分布式数据库。
3. 时间的践行者,立志成为一名讲师。
【我的成绩】
1. 为了走出农村,2次高考
一次考研失败,
遇挫之后不知道干什么,开启被动之旅。
2. 为了找到合适工作,
深入研究c++书籍和leetcode 200题目
3. 为了提高项目能力,参与开源项目建设。
4. 为了把简单事情说清楚/要干啥
按照《只管去做》,《福格行为模型>>方法。
纸上得来终觉浅,绝知此事要躬行
做一个践行者。
【我能提供】
1. 后端程序员的简历优化+就业辅导+职业规划
2. 全栈工程师(c++,rust,go,python )项目开发
3. 一年践行12本书践行记录。
【希望一起解决什么,开启破圈之旅】
1. 交接更多朋友,抱团取暖。
寻找意义本身就更加有意义。
2. 无法做整个系统,聚焦一个模块
道可道也,非恒道也
名可名也,非恒名也。
无名 万物之始也
有名 万物之母也
别想太多,只管去做,躬身入局
链接我: # + v(github):watchpoints
#众号:后端开发成长指南
**/
이 글은 작성자입니다 엠디나이스다중 플랫폼 출판