Mi informacion de contacto
Correo[email protected]
2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
Hola a todos
Hoy completé el campamento de capacitación sobre desarrollo del sistema operativo de conducción autónoma 2024: la cuarta fase del campamento de primaria - Tutorial
Día 2 Practica el lenguaje Rust con susurros-Move Semantics
https://doc.rust-lang.org/stable/book/ch04-00-entendiendo-la-propiedad.html
Cuando envío el código, recibo un mensaje que dice que no tengo permiso. ¿Cómo salgo?
acción
Configuración del entorno de desarrollo de referencia.
https://rcore-os.cn/libro-tutorial-de-arceos/caps01-02.html
mi tema
https://github.com/cicvedu/rustlings-semestre-4-puntos-de-vigilancia
Cree una clave ssh para clonar el código de github a través de ssh. En el entorno Linux, utilice el comando ssh-keygen -t rsa -b 4096 -C "su buzón" para crear una clave ssh. Simplemente presione Entrar para ver todas las opciones siguientes. Luego usa cat ~/.ssh/id_rsa.pub
Rust tiene un par de tipos básicos que se implementan directamente en el compilador. En esta sección, repasaremos los más importantes.
Tipo Slice Las rebanadas le permiten hacer referencia a una secuencia contigua de elementos en una colección en lugar de a toda la colección.
Una porción es una especie de referencia, por lo que no tiene propiedad.
En Rust, un sector es una vista que hace referencia a una secuencia de elementos contiguos de una matriz u otro sector. Para crear un sector, debe especificar las posiciones inicial y final del sector (sin incluir el índice de la posición final).en matriza
en si quieres conseguir[2, 3, 4]
Para este segmento, debe comenzar en el índice 1 y terminar en el índice 4 (sin incluir el índice 4).
A continuación le indicamos cómo corregir su código de prueba:
#[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);
}
En este ejemplo,&a[1..4]
Creó una matriz dea
El segmento comienza en el índice 1 y termina en el índice 3, porque la sintaxis de corte de Rust es un intervalo cerrado por la izquierda y abierto por la derecha (incluido el inicio, pero no el final).entoncesnice_slice
Contiene la matriza
medio[2, 3, 4]
。
Ingrese Rustlings Watch en la línea de comando para iniciar el experimento de bucle de edición del código.
Entendiendo la propiedad
La propiedad es la característica más exclusiva de Rust y tiene profundas implicaciones para el resto del lenguaje.
Permite a Rust realizar garantías de seguridad de memoria sin necesidad de un recolector de basura.
¿Qué es la propiedad?
Reglas de propiedad Primero, echemos un vistazo a las reglas de propiedad. Tenga en cuenta estas reglas mientras trabajamos con los ejemplos que las ilustran:
El ejemplo de código en sí es correcto y demuestra los conceptos de propiedad y copia en Rust. Sin embargo, si desea asegurarse de que su código se compila y se ejecuta, y desea abordar algunas posibles mejoras o correcciones, aquí tiene algunas sugerencias:
Cerciorarse takes_ownership
ymakes_copy
funcionar enmain
función definida antes, porque las funciones en Rust deben declararse primero y luego usarse.
agregar notas, explicar por qué s
existirtakes_ownership
no se puede utilizar después de haber sido llamado, yx
existirmakes_copy
Todavía se puede utilizar después de haber sido llamado.
añadir main
tipo de retorno de función, aunque esto no es necesario en programas simples, es una buena práctica de programación.
Usando las herramientas de formato de Rust,Por ejemplo rustfmt
, para mantener el código limpio.
Aquí está el código modificado basado en las sugerencias anteriores:
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);
}
En esta versión revisada hemos agregado main
tipo de retorno de función()
,esto significa main
La función no devuelve ningún valor.Además, se añaden comentarios para explicar por qué.s
existirtakes_ownership
no se puede utilizar después de haber sido llamado, yx
existirmakes_copy
Sigue siendo válido después de llamar.Además, mostramos intentos detakes_ownership
Usar después de llamars
Ejemplos que causarían errores de compilación, yx
existirmakes_copy
Ejemplos que aún se pueden utilizar después de llamar.
Los vectores son una de las estructuras de datos de Rust más utilizadas.
En otros lenguajes de programación, simplemente se llamarían matrices, pero como Rust opera en un nivel un poco más bajo, una matriz en Rust se almacena en la pila (lo que significa que no puede crecer ni reducirse, y el tamaño debe conocerse en el momento de la compilación), y un vector se almacena en el montón (donde estas restricciones no se aplican).
Los vectores son un capítulo más adelante en el libro, pero creemos que son lo suficientemente útiles como para hablar de ellos un poco antes. Hablaremos de otra estructura de datos útil, los mapas hash, más adelante.
vec_map
La función es aceptar unaVec<i32>
tipo (es decir, un vector que contiene un entero de 32 bits), luego devuelve un nuevoVec<i32>
, cada elemento de este nuevo vector tiene el doble de tamaño que el elemento correspondiente del vector original.
Específicamente,vec_map
en funciónmap
ycollect
El método funciona así:
**v.iter()
**: Este método crea un iterador que atraviesa v
cada elemento del vector.iter
El iterador devuelto por el método proporciona una referencia inmutable a los elementos del vector.
**.map(|element| { element * 2 })
**:map
El método acepta un cierre (función anónima), en este caso el cierre acepta un parámetroelement
(una referencia inmutable a un elemento en el vector), luego devuelve el valor de este elemento multiplicado por 2.Operaciones dentro de cierreselement * 2
De hecho, está desreferenciando los datos señalados por la referencia (a través de*
operador) y realizar operaciones de multiplicación.
**.collect()
**:map
El método devuelve un iterador diferido que aplica las operaciones del cierre una por una, pero no recopila los resultados inmediatamente.collect
Se llama al método para pasar estosmap
Los elementos procesados se recogen en un nuevoVec<i32>
en vectores.
usar map
ycollect
El beneficio es que le permiten realizar operaciones en cada elemento de la colección de forma declarativa y recopilar los resultados en una nueva colección sin la necesidad de escribir un bucle explícito. De esta forma el código es más conciso y más consistente con el estilo Rust.
Aquí se explica cómo utilizar vec_map
Ejemplo de función:
fn main() {
let original_vec = vec![1, 2, 3, 4];
let doubled_vec = vec_map(&original_vec);
println!("{:?}", doubled_vec); // 这将打印:[2, 4, 6, 8]
}
En este ejemplo,vec_map
tomar el controloriginal_vec
referencia, creando un nuevo vectordoubled_vec
, que contiene el doble del valor de cada elemento del vector original y lo imprime.
Estos ejercicios están adaptados de Pnk Félix's Tutorial de óxido - ¡¡¡Gracias Félix!!!
Para esta sección, los enlaces a libros son especialmente importantes.
Existe una regla para las referencias mutables en Rust: en cualquier momento dado, puede tener cualquier cantidad de referencias inmutables, o como máximo una referencia mutable. Esta regla garantiza la seguridad de la memoria y evita las carreras de datos.
En el código proporcionado, hay un problema:main
La función intentó crear dos referencias mutables.y
yz
, ambos apuntan a la misma variable x
. Esto no está permitido porque las reglas de préstamo de Rust no permiten múltiples referencias mutables a la misma variable en el mismo alcance. Por eso el código no se compila.
Para solucionar este problema, debe asegurarse de que solo exista una referencia mutable en un momento dado. Aquí está el código fijo:
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,这是正确的
}
En esta versión fija, nos aseguramos de que solo exista una referencia mutable en cualquier momento mediante la creación de un alcance interno.Primero, creamosy
alcance, se realizan operaciones en él, y luego este alcance finaliza,y
Ya no es valido.Después de eso, creamosz
alcance, nuevamente parax
Realizar operaciones. Esto sigue las reglas de préstamo de Rust para que el código se compile y se ejecute como se esperaba.
Este mensaje de error de compilación apunta a un problema del ciclo de vida en el código Rust.El problema esstring_uppercase
En la implementación de la función se intenta asignar un valor temporal a una referencia, lo cual no está permitido.
Aquí está la línea de código que sale mal:
data = &data.to_uppercase();
En esta línea de código,data.to_uppercase()
Creo unString
una nueva instancia dedata
prestado.Sin embargo, intente asignar una referencia a este valor temporal paradata
es ilegal porque el valor temporal se destruye inmediatamente al final de la declaración, ydata
Requiere una vida útil más larga que los valores temporales.
Para solucionar este problema necesitamos modificar string_uppercase
Una función que acepta una referencia mutable y se llama directamente sobre los datos señalados por la referencia.make_uppercase()
método en lugar de intentar reasignar. Aquí está el código fijo:
fn string_uppercase(data: &mut String) {
data.make_uppercase(); // 直接在 data 上调用 make_uppercase 方法
println!("{}", data);
}
En esta versión fija hemos eliminado mut data: &String
mediomut
,porque data
Ya es una referencia mutable.Entonces nosotros directamentedata
recurrirmake_uppercase()
, por lo que no habrá problema con los valores temporales.make_uppercase()
El método será modificado.data
puntos de referencia aString
instancia sin crear una nuevaString
。
también,main
La llamada dentro de la función también debe actualizarse en consecuencia para pasar una referencia mutable:
fn main() {
let mut data = "Rust is great!".to_string();
string_uppercase(&mut data); // 传递一个可变引用
println!("{}", data); // 打印修改后的字符串
}
Ahora,string_uppercase
la función aceptadata
una referencia mutable, modifíquela directamente ymain
en funcióndata
es mutable y puede serstring_uppercase
modificado. De esta manera el código se compila y funciona como se esperaba.
/**
【昵称】小王同学
【坐标】山东
【自我介绍】
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
#众号:后端开发成长指南
**/
Este artículo está escrito por mdnicePublicación multiplataforma