¿Por qué tiene Rust String
y str
? ¿Cuáles son las diferencias entre String
y str
? ¿Cuándo se usa uno en String
lugar de str
y viceversa? ¿Uno de ellos está en desuso?
String
es el tipo de cadena dinámico dinámico, como Vec
: utilícelo cuando necesite poseer o modificar sus datos de cadena.
str
es una secuencia inmutable de 1 UTF-8 bytes de longitud dinámica en algún lugar de la memoria. Como el tamaño es desconocido, solo se puede manejar detrás de un puntero. Esto significa que str
más comúnmente 2 aparece como &str
: una referencia a algunos datos UTF-8, normalmente llamados "corte de cadena" o simplemente un "corte". Un segmento es solo una vista de algunos datos, y esos datos pueden estar en cualquier lugar, por ejemplo
"foo"
es a &'static str
. Los datos se codifican en el ejecutable y se cargan en la memoria cuando se ejecuta el programa.String
: String
desreferencias a una &str
vista de los String
datos del 's.En la pila : por ejemplo, lo siguiente crea una matriz de bytes asignada a la pila y luego obtiene una vista de esos datos como&str
:
use std::str;
let x: &[u8] = &[b'a', b'b', b'c'];
let stack_str: &str = str::from_utf8(x).unwrap();
En resumen, úselo String
si necesita datos de cadena propios (como pasar cadenas a otros hilos o construirlos en tiempo de ejecución), y úselo &str
si solo necesita una vista de una cadena.
Esto es idéntico a la relación entre un vector Vec<T>
y un corte &[T]
, y es similar a la relación entre el valor T
y la referencia &T
para los tipos generales.
1 A str
es de longitud fija; no puede escribir bytes más allá del final, ni dejar bytes finales inválidos. Como UTF-8 es una codificación de ancho variable, esto obliga a todos los str
s a ser inmutables en muchos casos. En general, la mutación requiere escribir más o menos bytes que antes (por ejemplo, reemplazar un a
(1 byte) con un ä
(2+ bytes) requeriría hacer más espacio en el str
). Existen métodos específicos que pueden modificar un &str
lugar, principalmente aquellos que manejan solo caracteres ASCII, como make_ascii_uppercase
.
2 Los tipos de tamaño dinámico permiten cosas como Rc<str>
una secuencia de bytes UTF-8 contados de referencia desde Rust 1.2. Rust 1.21 permite crear fácilmente estos tipos.
&str
está formado por dos componentes: un puntero a algunos bytes y una longitud".[u8; N]
.Rc<str>
yArc<str>
ahora se pueden usar a través de la biblioteca estándar.Tengo experiencia en C ++ y me pareció muy útil pensar
String
y&str
en términos de C ++:String
es como unstd::string
; posee la memoria y hace el trabajo sucio de administrar la memoria.&str
es como unchar*
(pero un poco más sofisticado); nos señala el comienzo de un fragmento de la misma manera en que puede obtener un puntero al contenido destd::string
.¿Alguno de ellos va a desaparecer? No lo creo. Tienen dos propósitos:
String
mantiene el búfer y es muy práctico de usar.&str
es liviano y debe usarse para "mirar" en cuerdas. Puede buscar, dividir, analizar e incluso reemplazar fragmentos sin necesidad de asignar nueva memoria.&str
puede mirar dentro de una,String
ya que puede apuntar a una cadena literal. El siguiente código debe copiar la cadena literal en laString
memoria administrada:El siguiente código le permite usar el literal en sí mismo sin copia (aunque solo lectura)
fuente
str
, solo se usa como&str
, es un segmento de cadena, una referencia a una matriz de bytes UTF-8.String
es lo que solía ser~str
, una matriz de bytes UTF-8 que se puede crecer y poseer.fuente
~str
ahora esBox<str>
~str
era cultivable mientrasBox<str>
que no es cultivable. (Eso~str
y~[T]
fueron mágicamente cultivables, a diferencia de cualquier otro objeto~
, fue exactamente por quéString
yVec<T>
se introdujeron, de modo que las reglas fueron directas y consistentes.)En realidad son completamente diferentes. En primer lugar, a
str
no es más que una cosa de nivel de tipo; solo se puede razonar a nivel de tipo porque es un tipo denominado de tamaño dinámico (DST). El tamaño questr
ocupa no se puede conocer en tiempo de compilación y depende de la información de tiempo de ejecución; no se puede almacenar en una variable porque el compilador necesita saber en tiempo de compilación cuál es el tamaño de cada variable. Astr
es conceptualmente solo una fila deu8
bytes con la garantía de que forma un UTF-8 válido. ¿Qué tan grande es la fila? Nadie lo sabe hasta el tiempo de ejecución, por lo tanto, no se puede almacenar en una variable.Lo interesante es que una
&str
o cualquier otro puntero a unastr
comoBox<str>
lo hace existir en tiempo de ejecución. Este es un llamado "indicador gordo"; es un puntero con información adicional (en este caso, el tamaño de la cosa a la que apunta), por lo que es el doble de grande. De hecho, a&str
está bastante cerca de aString
(pero no a&String
). A&str
son dos palabras; un puntero al primer byte de aystr
otro número que describe cuántos bytes tiene la longitud delstr
.Contrariamente a lo que se dice, a
str
no necesita ser inmutable. Si puede obtener un&mut str
como puntero exclusivo para elstr
, puede mutarlo y todas las funciones seguras que lo mutan garantizan que la restricción UTF-8 se mantenga porque si se viola, entonces tenemos un comportamiento indefinido ya que la biblioteca asume que esta restricción es cierto y no lo comprueba.Entonces, ¿qué es un
String
? Eso son tres palabras; dos son los mismos que para&str
pero agrega una tercera palabra que es la capacidad delstr
búfer en el montón, siempre en el montón (astr
no está necesariamente en el montón) que administra antes de que se llene y tenga que reasignarse. elString
básicamente posee unastr
como dicen; lo controla y puede cambiar su tamaño y reasignarlo cuando lo considere conveniente. Entonces aString
es como se dice más cerca de a&str
que a astr
.Otra cosa es una
Box<str>
; esto también posee astr
y su representación en tiempo de ejecución es la misma que a&str
pero también posee lastr
diferencia,&str
pero no puede cambiar su tamaño porque no conoce su capacidad, por lo que básicamenteBox<str>
se puede ver como una longitud fijaString
que no se puede cambiar de tamaño (puede siempre conviértalo en unString
si desea cambiar su tamaño).Existe una relación muy similar entre
[T]
yVec<T>
excepto que no hay restricción UTF-8 y puede contener cualquier tipo cuyo tamaño no sea dinámico.El uso de
str
en el nivel de tipo es principalmente para crear abstracciones genéricas con&str
; existe en el nivel de tipo para poder escribir rasgos convenientemente. En teoría,str
como una cosa tipo no necesitaba existir y solo&str
eso significaría que se tendría que escribir una gran cantidad de código adicional que ahora puede ser genérico.&str
es súper útil para poder tener múltiples subcadenas diferentes de aString
sin tener que copiar; como se dijo,String
posee elstr
en el montón que administra y si solo pudiera crear una subcadena de aString
con un nuevoString
, tendría que copiarlo porque todo en Rust solo puede tener un único propietario para lidiar con la seguridad de la memoria. Entonces, por ejemplo, puede cortar una cadena:Tenemos dos subcadenas diferentes
str
de la misma cadena.string
es el propietario delstr
búfer completo real en el montón y las&str
subcadenas son solo punteros gordos a ese búfer en el montón.fuente
std::String
es simplemente un vector deu8
. Puede encontrar su definición en el código fuente . Está asignado al montón y puede crecer.str
es un tipo primitivo, también llamado corte de cadena . Un corte de cadena tiene un tamaño fijo. Una cadena literal comolet test = "hello world"
tiene&'static str
tipo.test
es una referencia a esta cadena asignada estáticamente.&str
no se puede modificar, por ejemplo,str
tiene una porción mutable&mut str
, por ejemplo:pub fn split_at_mut(&mut self, mid: usize) -> (&mut str, &mut str)
Pero un pequeño cambio en UTF-8 puede cambiar la longitud de su byte, y un segmento no puede reasignar su referente.
fuente
En palabras sencillas, el
String
tipo de datos se almacena en el montón (al igual queVec
) y tiene acceso a esa ubicación.&str
Es un tipo de corte. Eso significa que es solo referencia a un ya presenteString
en algún lugar del montón.&str
no hace ninguna asignación en tiempo de ejecución. Entonces, por razones de memoria, puede usar&str
másString
. Pero tenga en cuenta que al usarlo&str
puede tener que lidiar con vidas explícitas.fuente
str
es queview
ya está presenteString
en el montón.Para personas de C # y Java:
String
===StringBuilder
&str
Cadena de óxido === (inmutable)Me gusta pensar en a
&str
como una vista en una cadena, como una cadena interna en Java / C # donde no puede cambiarla, solo cree una nueva.fuente
Aquí hay una explicación rápida y fácil.
String
- Una estructura de datos atribuible a almacenamiento dinámico que se puede crecer. Se puede obligar a a&str
.str
- es (ahora, a medida que Rust evoluciona) una cadena mutable de longitud fija que vive en el montón o en el binario. Solo puede interactuar constr
un tipo prestado a través de una vista de corte de cadena, como&str
.Consideraciones de uso:
Prefiera
String
si desea poseer o mutar una cadena, como pasar la cadena a otro hilo, etc.Prefiere
&str
si quieres tener una vista de solo lectura de una cadena.fuente