Rust by Example — страница 41 из 66

// Copy `Unit`, there are no resources to move

let copied_unit = unit;

// Both `Unit`s can be used independently

println!("original: {:?}", unit);

println!("copy: {:?}", copied_unit);

// Instantiate `Pair`

let pair = Pair(Box::new(1), Box::new(2));

println!("original: {:?}", pair);

// Move `pair` into `moved_pair`, moves resources

let moved_pair = pair;

println!("moved: {:?}", moved_pair);

// Error! `pair` has lost its resources

//println!("original: {:?}", pair);

// TODO ^ Try uncommenting this line

// Clone `moved_pair` into `cloned_pair` (resources are included)

let cloned_pair = moved_pair.clone();

// Drop the original pair using std::mem::drop

drop(moved_pair);

// Error! `moved_pair` has been dropped

//println!("copy: {:?}", moved_pair);

// TODO ^ Try uncommenting this line

// The result from .clone() can still be used!

println!("clone: {:?}", cloned_pair);

}

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

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Supertraits

Rust doesn't have "inheritance", but you can define a trait as being a superset of another trait. For example:

trait Person {

fn name(&self) -> String;

}

// Person is a supertrait of Student.

// Implementing Student requires you to also impl Person.

trait Student: Person {

fn university(&self) -> String;

}

trait Programmer {

fn fav_language(&self) -> String;

}

// CompSciStudent (computer science student) is a subtrait of both Programmer

// and Student. Implementing CompSciStudent requires you to impl both supertraits.

trait CompSciStudent: Programmer + Student {

fn git_username(&self) -> String;

}

fn comp_sci_student_greeting(student: &dyn CompSciStudent) -> String {

format!(

"My name is {} and I attend {}. My favorite language is {}. My Git username is {}",

student.name(),

student.university(),

student.fav_language(),

student.git_username()

)

}

fn main() {}

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

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

See also:

The Rust Programming Language chapter on supertraits

Disambiguating overlapping traits

A type can implement many different traits. What if two traits both require the same name? For example, many traits might have a method named get(). They might even have different return types!

Good news: because each trait implementation gets its own impl block, it's clear which trait's get method you're implementing.

What about when it comes time to call those methods? To disambiguate between them, we have to use Fully Qualified Syntax.

trait UsernameWidget {

// Get the selected username out of this widget

fn get(&self) -> String;

}

trait AgeWidget {

// Get the selected age out of this widget

fn get(&self) -> u8;

}

// A form with both a UsernameWidget and an AgeWidget

struct Form {

username: String,

age: u8,

}

impl UsernameWidget for Form {

fn get(&self) -> String {

self.username.clone()

}

}

impl AgeWidget for Form {

fn get(&self) -> u8 {

self.age

}

}

fn main() {

let form = Form{

username: "rustacean".to_owned(),

age: 28,

};

// If you uncomment this line, you'll get an error saying

// "multiple `get` found". Because, after all, there are multiple methods

// named `get`.

// println!("{}", form.get());

let username = 
::get(&form);

assert_eq!("rustacean".to_owned(), username);

let age = ::get(&form);

assert_eq!(28, age);

}

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

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

See also:

The Rust Programming Language chapter on Fully Qualified syntax

macro_rules!

Rust provides a powerful macro system that allows metaprogramming. As you've seen in previous chapters, macros look like functions, except that their name ends with a bang !, but instead of generating a function call, macros are expanded into source code that gets compiled with the rest of the program. However, unlike macros in C and other languages, Rust macros are expanded into abstract syntax trees, rather than string preprocessing, so you don't get unexpected precedence bugs.

Macros are created using the macro_rules! macro.

// This is a simple macro named `say_hello`.

macro_rules! say_hello {

// `()` indicates that the macro takes no argument.

() =