Выбрать главу

use std::marker::PhantomData;

// A phantom tuple struct which is generic over `A` with hidden parameter `B`.

#[derive(PartialEq)] // Allow equality test for this type.

struct PhantomTuple<A, B>(A,PhantomData<B>);

// A phantom type struct which is generic over `A` with hidden parameter `B`.

#[derive(PartialEq)] // Allow equality test for this type.

struct PhantomStruct<A, B> { first: A, phantom: PhantomData<B> }

// Note: Storage is allocated for generic type `A`, but not for `B`.

// Therefore, `B` cannot be used in computations.

fn main() {

// Here, `f32` and `f64` are the hidden parameters.

// PhantomTuple type specified as `<char, f32>`.

let _tuple1: PhantomTuple<char, f32> = PhantomTuple('Q', PhantomData);

// PhantomTuple type specified as `<char, f64>`.

let _tuple2: PhantomTuple<char, f64> = PhantomTuple('Q', PhantomData);

// Type specified as `<char, f32>`.

let _struct1: PhantomStruct<char, f32> = PhantomStruct {

first: 'Q',

phantom: PhantomData,

};

// Type specified as `<char, f64>`.

let _struct2: PhantomStruct<char, f64> = PhantomStruct {

first: 'Q',

phantom: PhantomData,

};

// Compile-time Error! Type mismatch so these cannot be compared:

//println!("_tuple1 == _tuple2 yields: {}",

// _tuple1 == _tuple2);

// Compile-time Error! Type mismatch so these cannot be compared:

//println!("_struct1 == _struct2 yields: {}",

// _struct1 == _struct2);

}

הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Derive, struct, and TupleStructs

A useful method of unit conversions can be examined by implementing Add with a phantom type parameter. The Add trait is examined below:

// This construction would impose: `Self + RHS = Output`

// where RHS defaults to Self if not specified in the implementation.

pub trait Add<RHS = Self> {

type Output;

fn add(self, rhs: RHS) -> Self::Output;

}

// `Output` must be `T<U>` so that `T<U> + T<U> = T<U>`.

impl<U> Add for T<U> {

type Output = T<U>;

...

}

The whole implementation:

use std::ops::Add;

use std::marker::PhantomData;

/// Create void enumerations to define unit types.

#[derive(Debug, Clone, Copy)]

enum Inch {}

#[derive(Debug, Clone, Copy)]

enum Mm {}

/// `Length` is a type with phantom type parameter `Unit`,

/// and is not generic over the length type (that is `f64`).

///

/// `f64` already implements the `Clone` and `Copy` traits.

#[derive(Debug, Clone, Copy)]

struct Length<Unit>(f64, PhantomData<Unit>);

/// The `Add` trait defines the behavior of the `+` operator.

impl<Unit> Add for Length<Unit> {

type Output = Length<Unit>;

// add() returns a new `Length` struct containing the sum.

fn add(self, rhs: Length<Unit>) -> Length<Unit> {

// `+` calls the `Add` implementation for `f64`.

Length(self.0 + rhs.0, PhantomData)

}

}

fn main() {

// Specifies `one_foot` to have phantom type parameter `Inch`.

let one_foot: Length<Inch> = Length(12.0, PhantomData);

// `one_meter` has phantom type parameter `Mm`.

let one_meter: Length<Mm> = Length(1000.0, PhantomData);

// `+` calls the `add()` method we implemented for `Length<Unit>`.

//

// Since `Length` implements `Copy`, `add()` does not consume

// `one_foot` and `one_meter` but copies them into `self` and `rhs`.

let two_feet = one_foot + one_foot;

let two_meters = one_meter + one_meter;

// Addition works.

println!("one foot + one_foot = {:?} in", two_feet.0);

println!("one meter + one_meter = {:?} mm", two_meters.0);

// Nonsensical operations fail as they should:

// Compile-time Error: type mismatch.

//let one_feter = one_foot + one_meter;

}

הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Borrowing (&), Bounds (X: Y), enum, impl & self, Overloading, ref, Traits (X for Y), and TupleStructs.