2016-08-27 1 views
0

Voici un exemple de transmuter un type Sized d'un pointeur brut:Comment créer un type? Sized à partir d'un pointeur brut?

use std::mem; 

#[derive(Eq, PartialEq)] 
#[repr(packed)] 
struct Bob { 
    id: u32, 
    age: u32, 
} 

unsafe fn get_type<'a, T: Sized>(p: *const u8) -> &'a T { 
    mem::transmute(p) 
} 

#[test] 
fn it_works() { 
    let bob = Bob { 
     id: 22, 
     age: 445, 
    }; 
    let bob2: &Bob = unsafe { 
     let ptr: *const u8 = mem::transmute(&bob); 
     get_type(ptr) 
    }; 
    assert_eq!(&bob, bob2); 
} 

Cependant, pour ma demande, je veux être en mesure d'obtenir un type ?Sized au lieu d'un type Sized. Cependant, cela ne fonctionne pas:

unsafe fn get_type2<'a, T: ?Sized>(p: *const u8) -> &'a T { 
    mem::transmute(p) 
} 

Il échoue avec ce message d'erreur:

error: transmute called with differently sized types: *const u8 (64 bits) to &'a T (pointer to T) [--explain E0512] 
--> src/main.rs:2:9 
    |> 
2 |>   mem::transmute(p) 
    |>   ^^^^^^^^^^^^^^ 

J'ai essayé de lui donner un &[u8] (pointeur de la graisse) en le convertissant en utilisant std::slice::from_raw_parts, mais il échoue avec à peu près le même message d'erreur.

Répondre

6

Vous ne pouvez pas réellement pour la raison même citée dans le message d'erreur.

références de rouille peuvent être soit de taille pointeur (pour Sized types) ou plus gros (pour !Sized types). Par exemple, si Trait est un trait, une référence &Trait est en fait deux champs tels que définis par std::raw::TraitObject.

Ainsi, afin de former une référence à un type non collé, vous devez:

  • identifier exactement quel genre de type il est non encollé (? Trait tranche ...)
  • ramasser la représentation droite (std::raw::TraitObject, std::raw::Slice, ...)

et vous devez remplir les espaces vides (il est plus qu'un simple pointeur). Donc, à moins que vous ne puissiez limiter votre fonction à &T where T: Sized, vous ne pouvez pas simplement transformer un pointeur brut en &T.

+0

l'ai obtenu, donc je suppose que le compilateur gère magiquement tout cela pour le cas d'utilisation normal? (qui est ce que cela signifiait que «Sized» est un «compilateur intrinsèque ...) - aussi vous avez dit«! Sized »et je pense que vous vouliez dire«? Sized » – vitiral

+3

@cloudformdesign: Je voulais dire«! Sized ». 'Sized' signifie taille,'! Sized' signifie pas dimensionné (mais ne peut pas être réellement utilisé comme une limite) et '? Sized' signifie taille peut-être.En ce qui concerne les conversions de gestion du compilateur: en effet, le compilateur ne fait qu'emballer/décompresser Notez que les deux méthodes 'raw :: TraitObject' et' raw :: Slice' sont instables comme principe pour permettre l'évolution de la représentation sous-jacente, et resteront probablement instables "pour toujours" car Rust n'est pas une parenté sur un commit stable ABI –

+0

génial! Merci pour le bon aperçu – vitiral