traduccion ps4 lenguaje language descargar rust

ps4 - rust traduccion



¿Cómo creo un singleton global mutable? (1)

Respuesta sin respuesta

Evitar el estado global en general. En cambio, construya el objeto en algún lugar temprano (tal vez en main ), luego pase referencias mutables a ese objeto en los lugares que lo necesitan. Por lo general, esto hará que su código sea más fácil de razonar y no requiere tanto doblarse hacia atrás.

Mírate en el espejo antes de decidir que quieres variables mutables globales. Hay casos raros en los que es útil, por eso vale la pena saber cómo hacerlo.

¿Todavía quieres hacer uno ...?

Usando lazy-static

La caja lazy-static puede eliminar parte del trabajo pesado de crear un singleton (abajo). Aquí hay un vector mutable global:

#[macro_use] extern crate lazy_static; use std::sync::Mutex; lazy_static! { static ref ARRAY: Mutex<Vec<u8>> = Mutex::new(vec![]); } fn do_a_call() { ARRAY.lock().unwrap().push(1); } fn main() { do_a_call(); do_a_call(); do_a_call(); println!("called {}", ARRAY.lock().unwrap().len()); }

Si elimina el Mutex entonces tiene un singleton global sin ninguna mutabilidad.

Un caso especial: atómica

Si solo necesita rastrear un valor entero, puede usar directamente un atomic :

use std::sync::atomic::{AtomicUsize, Ordering}; static CALL_COUNT: AtomicUsize = AtomicUsize::new(0); fn do_a_call() { CALL_COUNT.fetch_add(1, Ordering::SeqCst); } fn main() { do_a_call(); do_a_call(); do_a_call(); println!("called {}", CALL_COUNT.load(Ordering::SeqCst)); }

Implementación manual sin dependencia

Esto se basa en gran medida en la implementación Rust 1.0 de stdin . También debe mirar la implementación moderna de io::Lazy . He comentado en línea con lo que hace cada línea.

use std::sync::{Arc, Mutex, Once, ONCE_INIT}; use std::time::Duration; use std::{mem, thread}; #[derive(Clone)] struct SingletonReader { // Since we will be used in many threads, we need to protect // concurrent access inner: Arc<Mutex<u8>>, } fn singleton() -> SingletonReader { // Initialize it to a null value static mut SINGLETON: *const SingletonReader = 0 as *const SingletonReader; static ONCE: Once = ONCE_INIT; unsafe { ONCE.call_once(|| { // Make it let singleton = SingletonReader { inner: Arc::new(Mutex::new(0)), }; // Put it in the heap so it can outlive this call SINGLETON = mem::transmute(Box::new(singleton)); }); // Now we give out a copy of the data that is safe to use concurrently. (*SINGLETON).clone() } } fn main() { // Let''s use the singleton in a few threads let threads: Vec<_> = (0..10) .map(|i| { thread::spawn(move || { thread::sleep(Duration::from_millis(i * 10)); let s = singleton(); let mut data = s.inner.lock().unwrap(); *data = i as u8; }) }) .collect(); // And let''s check the singleton every so often for _ in 0u8..20 { thread::sleep(Duration::from_millis(5)); let s = singleton(); let data = s.inner.lock().unwrap(); println!("It is: {}", *data); } for thread in threads.into_iter() { thread.join().unwrap(); } }

Esto imprime:

It is: 0 It is: 1 It is: 1 It is: 2 It is: 2 It is: 3 It is: 3 It is: 4 It is: 4 It is: 5 It is: 5 It is: 6 It is: 6 It is: 7 It is: 7 It is: 8 It is: 8 It is: 9 It is: 9 It is: 9

Este código se compila con Rust 1.23.0. Las implementaciones reales de Stdin usan algunas características inestables para intentar liberar la memoria asignada, lo que este código no hace.

Realmente, probablemente quieras hacer que SingletonReader implemente a Deref y DerefMut para que no tengas que meter el objeto y bloquearlo tú mismo.

Todo este trabajo es lo que lazy-static hace por ti.

El significado de "global"

Tenga en cuenta que aún puede utilizar el alcance de Rust normal y la privacidad a nivel de módulo para controlar el acceso a una variable static o lazy_static . Esto significa que puede declararlo en un módulo o incluso dentro de una función y no será accesible fuera de ese módulo / función. Esto es bueno para controlar el acceso:

use lazy_static::lazy_static; // 1.2.0 fn only_here() { lazy_static! { static ref NAME: String = String::from("hello, world!"); } println!("{}", &*NAME); } fn not_here() { println!("{}", &*NAME); }

error[E0425]: cannot find value `NAME` in this scope --> src/lib.rs:12:22 | 12 | println!("{}", &*NAME); | ^^^^ not found in this scope

Sin embargo, la variable sigue siendo global, ya que existe una instancia de la misma en todo el programa.

¿Cuál es la mejor manera de crear y usar una estructura con una sola instancia en el sistema? Sí, esto es necesario, es el subsistema OpenGL, y hacer varias copias de este y pasarlo a todas partes agregaría confusión, en lugar de aliviarlo.

El singleton debe ser lo más eficiente posible. No parece posible almacenar un objeto arbitrario en el área estática, ya que contiene un Vec con un destructor. La segunda opción es almacenar un puntero (inseguro) en el área estática, apuntando a un singleton de montón asignado. ¿Cuál es la forma más conveniente y segura de hacer esto, manteniendo la sintaxis concisa?