arrays - que - ¿Cuál es la diferencia entre un sector y una matriz?
que es un vector y una matriz en programacion (2)
¿Por qué tanto &[u8]
como &[u8; 3]
&[u8; 3]
ok en este ejemplo?
fn main() {
let x: &[u8] = &[1u8, 2, 3];
println!("{:?}", x);
let y: &[u8; 3] = &[1u8, 2, 3];
println!("{:?}", y);
}
El hecho de que
&[T; n]
&[T; n]
puede forzar a&[T]
es el aspecto que los hace tolerables. - Chris Morgan
¿Por qué puede &[T; n]
&[T; n]
coaccionar a &[T]
? ¿En qué otras condiciones se produce esta coacción?
¿Por qué puede
&[T; n]
&[T; n]
coaccionar a&[T]
?
La otra respuesta explica por qué &[T; n]
&[T; n]
debería coaccionar a &[T]
, aquí explicaré cómo funciona el compilador que &[T; n]
&[T; n]
puede coaccionar a &[T]
.
Hay cuatro posibles coerciones en Rust :
Transitividad.
- Si
T
coerces aU
yU
coercen aV
, entoncesT
coerces aV
- Si
Debilitamiento del puntero
- eliminando la mutabilidad:
&mut T
→&T
y*mut T
→*const T
- conversión a puntero sin formato:
&mut T
→*mut T
y&T
→*const T
- eliminando la mutabilidad:
- Si
T: Deref<Target = U>
, entonces&T
obliga a&U
través del métododeref()
- (De manera similar, si
T: DerefMut
, entonces&mut T
coerces a&mut U
través dederef_mut()
)
- Si
Si
Ptr
es un "tipo de puntero" (por ejemplo,&T
,*mut T
,Box
,Rc
, etc.) yT: Unsize<U>
,Ptr<T>
obliga aPtr<U>
.El rasgo
Unsize
se implementa automáticamente para:-
[T; n]: Unsize<[T]>
-
T: Unsize<Trait>
dondeT: Trait
-
struct Foo<…> { …, field: T }: Unsize< struct Foo<…> { …, field: U }>
, siempre queT: Unsize<U>
(y algunas condiciones más para facilitar el trabajo al compilador )
-
(Rust reconoce a
Ptr<X>
como un "tipo de puntero" si implementaCoerceUnsized
. La regla real se establece como " siT: CoerceUnsized<U>
entoncesT
coerces aU
".)
La razón &[T; n]
&[T; n]
obliga a &[T]
es la regla 4: (a) el compilador genera el implemento Implementar impl Unsize<[T]> for [T; n]
impl Unsize<[T]> for [T; n]
para cada [T; n]
[T; n]
, y (b) la referencia &X
es un tipo de puntero. Usando estos, &[T; n]
&[T; n]
puede coaccionar a &[T]
.
[T; n]
[T; n]
es una matriz de longitud n
, representada como n
instancias T
adyacentes.
&[T; n]
&[T; n]
es puramente una referencia a esa matriz, representada como un puntero delgado a los datos.
[T]
es una porción, un tipo sin tamaño; Solo se puede utilizar a través de alguna forma de direccionamiento indirecto.
&[T]
, llamado sector, es un tipo de tamaño. Es un puntero grueso , representado como un puntero al primer elemento y a la longitud de la rebanada.
Por lo tanto, las matrices tienen su longitud conocida en tiempo de compilación, mientras que las longitudes de corte son una cuestión de tiempo de ejecución. Las matrices son ciudadanos de segunda clase en la actualidad en Rust, ya que no es posible formar genéricos de matriz. Existen implementaciones manuales de los diversos rasgos para [T; 0]
[T; 0]
, [T; 1]
[T; 1]
, & c. , típicamente hasta 32; Debido a esta limitación, los cortes son mucho más útiles en general. El hecho de que &[T; n]
&[T; n]
puede forzar a &[T]
es el aspecto que los hace tolerables.
Hay una implementación de fmt::Debug
para [T; 3]
[T; 3]
donde T
implementa Debug
, y otro para &T
donde T
implementa fmt::Debug
, y así como u8
implementa Debug
, &[u8; 3]
&[u8; 3]
también lo hace.
¿Por qué puede
&[T; n]
&[T; n]
coaccionar a&[T]
? En Rust, ¿cuándo ocurre la coacción?
Se coaccionará cuando sea necesario y en ningún otro momento. Puedo pensar en dos casos:
- donde algo espera un
&[T]
y le das un&[T; n]
&[T; n]
coercirá silenciosamente; - cuando llama a
x.starts_with(…)
en un[T; n]
[T; n]
observará que no existe tal método en[T; n]
[T; n]
, y así entra en juego el autoref y lo intenta&[T; n]
&[T; n]
, que no ayuda, y luego la coacción entra en juego e intenta&[T]
, que tiene un método llamadostarts_with
.
El fragmento [1, 2, 3].starts_with(&[1, 2])
muestra ambos.