2015-05-23 7 views
17

Wenn Sie einen Option<&T> haben, weiß der Compiler, dass NULL niemals ein möglicher Wert für &T und encodes the None variant as NULL instead ist. Dies ermöglicht eine platzsparende:Kann ich die "Nullzeigeroptimierung" für meine eigenen Nicht-Zeigertypen verwenden?

use std::mem; 

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

Wenn Sie jedoch das gleiche mit einem Nicht-Zeiger-Typ zu tun, gibt es keine zusätzlichen Bits, diesen Wert zu speichern, in und zusätzlichen Platz benötigt:

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>>()); 
} 

Im Allgemeinen ist dies korrekt. Allerdings möchte ich mich für die Optimierung anmelden, weil ich weiß, dass mein Typ bestimmte unmögliche Werte hat. Als erfundenes Beispiel könnte ich einen Spielercharakter haben, der ein Alter hat. Das Alter kann unbekannt sein, wird aber nie so hoch sein wie 255:

struct Age(u8); 

struct Player { 
    age: Option<Age>, 
} 

Ich möchte in der Lage sein, den Optimierer dieser Einschränkung zu informieren - Age nie 255 sein kann, so ist es sicher, dass etwas zu verwenden, Muster als None. Ist das möglich?

Antwort

13

Nein, Sie können nicht ... im Stall Rust. Wenn Sie bereit sind, zu einem nächtlichen Compiler zu gehen, können Sie core::nonzero::NonZero verwenden. Dies fungiert als ein Wrapper, der dem Compiler den Inhalt nie eine Literal Null enthält. Es ist auch, warum Option<Box<T>> Zeigergröße ist.

Hier ist ein Beispiel, wie ein Age erstellt und seine Nutzlast gelesen wird.

#![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

Ich gehe davon aus, dass 'NonZero' keine Nullwerte zulässt. Was ist mit anderen Werten als Null? In meinem Beispiel könnte Null gültig sein, 255 aber nicht. – Shepmaster

+1

@Shempmaster: Es ist fest auf Nicht-0 kodiert, ich nehme an, mit einem Merkmal und den zugehörigen Konstanten könnte man das erweitern ... aber jetzt müssen Sie sich mit Mathematik zufrieden geben. Wenn 255 Ihr magischer Wert ist, dann reicht das Anwenden einer '+ 1' auf den Speicher und von '-1' aus dem Speicher (mit Arithmetik), damit die 'NonZero'-Magie funktioniert :) –

+1

@MatthieuM. Natürlich muss ich einfach mehr Profiling machen, um zu sehen, ob es das wirklich wert ist. Weniger Bytes zu verwenden, scheint ein offensichtlicher Gewinn zu sein; Verwenden Sie weniger Bytes * und * Pflicht Mathematik überall ist weniger sicher. – Shepmaster

Verwandte Themen