Pregunta

&[T] me está confundiendo.

Ingenuamente asumí que como &T, &[T] era un puntero, es decir, una dirección de puntero numérico.

Sin embargo, he visto código como este, que me sorprendió bastante ver que funciona bien (simplificado con fines de demostración;pero ves código como este en muchas implementaciones 'as_slice()'):

extern crate core;
extern crate collections;

use self::collections::str::raw::from_utf8;
use self::core::raw::Slice;
use std::mem::transmute;

fn main() {
  let val = "Hello World";
  {
    let value:&str;
    {
      let bytes = val.as_bytes();
      let mut slice = Slice { data: &bytes[0] as *const u8, len: bytes.len() };
      unsafe {
        let array:&[u8] = transmute(slice);
        value = from_utf8(array);
      }
      // slice.len = 0;
    }
    println!("{}", value);
  }
}

Entonces.

Inicialmente pensé que se trataba de un código no válido.

Es decir, la instancia de Slice creado dentro del alcance del bloque se devuelve fuera del alcance del bloque (mediante transmutación), y aunque el código se ejecuta, el println! en realidad está accediendo a datos que ya no son válidos a través de punteros inseguros.¡Malo!

...pero ese no parece ser el caso.

Considere comentar la línea. // slice.len = 0;

Este código todavía funciona bien (imprime 'Hola mundo') cuando esto sucede.

Entonces la línea...

value = from_utf8(array);

Si se trataba de un puntero no válido a la variable 'sector', el len en el println() La declaración sería 0, pero no lo es.De manera efectiva, una copia no solo de un valor de puntero, sino una copia completa del Slice estructura.

¿Está bien?

¿Eso significa que en general es válido devolver un &[T] siempre que el puntero de datos interno real sea válido, independientemente del alcance del original &[T] que se está devolviendo, porque un &[T] ¿La asignación es una operación de copia?

(Esto me parece extremadamente contrario a la intuición...entonces tal vez estoy entendiendo mal;si estoy en lo cierto, tener dos &[T] que apuntan a los mismos datos no pueden ser válidos, porque no sincronizarán las longitudes si modifica uno...)

¿Fue útil?

Solución

Una rebanada &[T], como habrás notado, es "equivalente" a una estructura std::raw::Slice.De hecho, Slice es una representación interna de &[T] valor, y sí, es un puntero y una longitud de datos detrás de ese puntero.A veces, esta estructura se denomina "puntero gordo", es decir, un puntero y una información adicional.

cuando pasas &[T] valor, de hecho solo estás copiando su contenido: el puntero y la longitud.

Si fuera un puntero no válido a la variable 'slice', el len en la declaración println() sería 0, pero no lo es.De manera efectiva, una copia no solo de un valor de puntero, sino una copia completa de la estructura de Slice.¿Está bien?

Entonces sí, exactamente.

¿Eso significa que, en general, es válido devolver un &[T] siempre que el puntero de datos interno real sea válido, independientemente del alcance del &[T] original que se devuelve, porque una asignación &[T] es una operación de copia?

Y esto también es cierto.Esa es la idea de las referencias prestadas, incluidas las porciones: las referencias prestadas se verifican estáticamente para su uso siempre que su referente esté vivo.Cuando finalmente llegue el horario de verano, las porciones y las referencias regulares estarán aún más unificadas.

(Esto me parece extremadamente contrario a la intuición...entonces tal vez estoy entendiendo mal;si estoy en lo cierto, tener dos &[T] que apunten a los mismos datos no puede ser válido, porque no sincronizarán las longitudes si modificas uno...)

Y ésta es en realidad una preocupación absolutamente válida;es uno de los problemas con el alias.Sin embargo, Rust está diseñado exactamente para evitar este tipo de errores.Hay dos cosas que hacen que el alias de sectores sea válido.

En primer lugar, los cortes no pueden cambiar de longitud;no hay métodos definidos en &[T] lo que le permitiría cambiar su longitud en su lugar.Puede crear un sector derivado a partir de un sector, pero será un objeto nuevo.

Pero incluso si los sectores no pueden cambiar de longitud, si los datos pudieran mutarse a través de ellos, aún podrían provocar un desastre si se les aplicara un alias.Por ejemplo, si los valores de los sectores son instancias de enumeración, la mutación de un valor en dicho sector con alias podría hacer que un puntero a los elementos internos del valor de enumeración contenido en este sector no sea válido.Entonces, en segundo lugar, los sectores con alias de Rust (&[T]) son inmutables.No puede cambiar los valores contenidos en ellos y no puede incorporar referencias mutables.

Estas dos características (y las comprobaciones del compilador para la vida útil) hacen que el alias de sectores sea absolutamente seguro.Sin embargo, a veces es necesario modificar los datos de un segmento.Y luego necesitas mudable rebanada, llamada &mut [T].Puede cambiar sus datos a través de dicho segmento;pero estas rebanadas son no aliasable.No puedes crear dos sectores mutables en la misma estructura (una matriz, por ejemplo), por lo que no puedes hacer nada peligroso.

Tenga en cuenta, sin embargo, que el uso transmute() transformar una rebanada en una Slice o viceversa es una operación insegura. &[T] Se garantiza estáticamente que será correcto si lo crea usando los métodos correctos, como llamar as_slice() en un Vec.Sin embargo, crearlo manualmente usando Slice estructura y luego transmutarla en &[T] es propenso a errores y puede fácilmente segmentar su programa, por ejemplo, cuando le asigna más longitud de la que realmente tiene asignada.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top