2015-05-23 5 views
17

Se si dispone di un Option<&T>, il compilatore sa che NULL non è mai un valore possibile per &T e encodes the None variant as NULL instead. Questo permette di risparmiare spazio:Posso utilizzare "ottimizzazione puntatore nullo" per i miei tipi non puntatore?

use std::mem; 

fn main() { 
    assert_eq!(mem::size_of::<&u8>(), mem::size_of::<Option<&u8>>()); 
} 

Tuttavia, se si fa la stessa cosa con un tipo non-pointer, non ci sono extra bit per memorizzare il valore e si richiede spazio extra:

use std::mem; 

fn main() { 
    // fails because left is 1 and right is 2 
    assert_eq!(mem::size_of::<u8>(), mem::size_of::<Option<u8>>()); 
} 

In generale, questo è corretto. Tuttavia, mi piacerebbe opt-in per l'ottimizzazione, perché so che il mio tipo ha determinati valori impossibili. Come esempio inventato, potrei avere un personaggio giocatore che ha un'età. L'età può essere sconosciuto, ma non sarà mai più in alto 255:

struct Age(u8); 

struct Player { 
    age: Option<Age>, 
} 

Mi piacerebbe essere in grado di informare l'ottimizzatore di questo vincolo - Age può mai essere 255, quindi è sicuro da usare quel po ' modello come None. È possibile?

risposta

13

No, non puoi ... in Rust stabile. Se sei disposto ad andare a un compilatore notturno, puoi utilizzare core::nonzero::NonZero. Questo funge da wrapper che comunica al compilatore che il contenuto non sarà mai contenere uno zero letterale. È anche il motivo per cui Option<Box<T>> è di dimensioni puntatore.

Ecco un esempio che mostra come creare un Age e leggere il suo carico utile.

#![feature(core)] 
#![allow(dead_code)] 

extern crate core; 

use core::nonzero::NonZero; 

struct Age(NonZero<u8>); 

impl Age { 
    pub fn new(age: u8) -> Age { 
     if age == 0 { panic!("Age cannot be zero!") } 
     Age(unsafe { NonZero::new(age) }) 
    } 

    pub fn age(&self) -> u8 { 
     *self.0 
    } 
} 

struct Player { 
    age: Option<Age>, 
} 

fn main() { 
    println!("size: {}", std::mem::size_of::<Player>()); 
    // Output: size: 1 
} 
+0

Passando al nome, suppongo che "NonZero" non consenta valori zero. Che dire dei valori diversi da zero? Nel mio esempio, zero potrebbe essere valido, ma 255 non lo è. – Shepmaster

+1

@Shepmaster: È hardcoded a non-0, suppongo che con un tratto e le costanti associate si possa estendere questo ... tuttavia per ora dovrete accontentarvi della matematica. Se 255 è il tuo valore magico, allora applicare '+ 1' alla memoria e' -1' proveniente dalla memoria (con l'aritmetica del wrapping) sarà sufficiente per il funzionamento della magia 'NonZero' :) –

+1

@MatthieuM. certamente, dovrò solo fare più profiling per vedere se ne vale veramente la pena. Usare meno byte sembra una vittoria ovvia; usare meno byte * e * la matematica obbligatoria ovunque è meno sicura. – Shepmaster

Problemi correlati