当前位置:网站首页>[rust notes] 09- special types and generics
[rust notes] 09- special types and generics
2022-07-03 08:35:00 【phial03】
09 - Special and generic
Rust The polymorphism of :
- Special type (trait)
- Generic (generic)
Special type :Rust Implementation of interfaces or abstract base classes .
The following is a special type of writing section
std::io::Write:trait Write { fn write(&mut self, buf: &[u8]) -> Result<usize>; fn flus(&mut self) -> Result<()>; fn write_all(&mut self, buf: &[u8]) -> Result<()> { ... } ... }The built-in feature is Rust Language provides hooks for operator overloading and other features (hook).
Generic : Generic functions or types can be used with many different types of values .
/// Given two values , Take the smaller value fn min<T: Ord>(value1: T, value2: T) -> T { if value1 <= value2 { value1 } else { value2 } }<T: Ord>representativeminYou can use the implementationOrdAny type parameter of special type T;- Statement
T: OrdIt's called binding .
9.1 - Use special type
- A feature is a feature of any type that you can choose to support or not . Common features :
- Realization
std::io::WriteThe value of can be used to write bytes ; - Realization
std::iter::IteratorThe value of can produce a sequence of values ; - Realization
std::clone::CloneThe value of can clone itself in memory ; - Realization
std::fmt::DebugThe value of can be usedprintln!()Of{:?}Format specifiers print out .
- Realization
- Common standard libraries realize the above features :
std::fs::FileRealizedWriteSpecial type , Bytes can be written to local files .std::net::TcpStreamIs to write bytes to the network connection .Vec<u8>It's also implementedWrite. Each call on the byte vector.write(), You can append some data at the end of the vector .Range<i32>RealizedIteratorSpecial type , And slice 、 Hash table and other related atmospheric types also realize this feature .- except
TcpStreamThis is not only the type of data in memory , Most standard library types implementCloneSpecial type . - Most standard libraries support
DebugSpecial type .
- The feature itself must be in the scope .
- You can use special types to add new methods to any type .
CloneandIteratorMethod , The default is always in scope . They are part of the standard front-end modules ,Rust It will be automatically imported into all modules .- Standard front module , The essence is a special set .
9.1.1 - Special target
Rust There are two ways to write polymorphic code using stereotypes : Special targets and generic .
Rust It is not allowed to declare
WriteVariable of type : Because the size of variables must be known at compile time , To achieveWriteThe type of can be any size .Special target : Point to a special type ( Like the one below
writer) References to , It has the commonality of quotation : Point to a value , There is a life cycle , It can bemutOr shared references .let mut buf: Vec<u8> = vec![]; let writer: &mut Write = &mut buf;The difference between special goals :Rust The type of reference target is usually unknown at compile time .
9.1.2 - Memory layout of special target
The special target is a fat pointer , Contains a pointer to a value and a pointer to a table representing the value type . Each special target occupies two machine words .
Rust When necessary, it will automatically convert ordinary references to special targets .
let mut local_file = File::create("hello.txt")?; // &mut local_file The type is &mut File say_hello(&mut local_file)?; // say_hello The parameter type of is &mut Write
9.1.3 - Generic functions
as follows
say_hello()Generic functions , Receive a special target as a parameter .fn say_hello<W: Write>(out: &mut W) -> std::io::Result<()> { out.write_all(b"hello world\n")?; out.flush() }<W: Write>Is a type parameter (type parameter), It means thatWriteA certain type of special type .- The type parameter is usually a capital letter .
Generic functions can have multiple type parameters :
fn run_query<M: Mapper + Serialize, R: Reducer + Serialize>(data: &DataSet, map: M, reduce: R) -> Results { ... }The binding of the above code is relatively long , have access to
wherekeyword , Express the above code structure clearly :fn run_query<M, R>(data: &DataSet, map: M, reduce: R) -> Results where M: Mapper + Serialize, R: Reducer + Serialize { ... }Such type parameters
MandRIt is still announced in advance , But the binding is transferred to the later .whereClause also applies to generic structures 、 enumeration 、 Type aliases and methods , Wherever binding is allowed .
Generic functions can have both lifetime parameters and type parameters . Lifetime parameters are written in front :
fn nearest<'t, 'c, P>(target: &'t P, candidates: &'c [P]) -> &'c P where P: MeasureDistance { ... }Besides functions , Other features also support generics :
Generic structs
Generic enumeration
Generic methods , Whether or not the type that defines the method is generic .
impl PancakeStack { fn push<T: Topping>(&mut self, goop: T) -> PancakeResult<()> { ... } }Generic type alias
type PancakeResult<T> = Result<T, PancakeError>;Generic and special
binding 、
whereClause 、 Life cycle parameters, etc , It can be applied to all generic feature items mentioned above .
9.1.4 - Use scenarios
- Define a mixed type value , Put it all together , It is recommended to use feature targets .
- Using special targets can reduce the total amount of compiled code , Prevent code bloat (code bloat), Suitable for making microcontrollers .
- Advantages of generics over special targets :
- Speed : Eliminate the time of dynamic search ;
- Not all special models support special goals . For example, static methods are only valid for generics , No special objects are considered at all .
9.2 - Define and implement features
Define the special type : Name it and list the type signatures of the special methods :
trait Visible { fn draw(&self, canvas: &mut Canvas); fn hit_test(&self, x: i32, y: i32) -> bool; }Realize special , Use
impl TraitName for Typegrammar :impl Visible for Broom { fn draw(&self, canvas: &mut Canvas) { for y in self.y - self.height - 1 .. self.y { canvas.write_at(self.x, y, '|'); } canvas.write_at(self.x, self.y, 'M'); } fn hit_test(&self, x: i32, y: i32) -> bool { self.x == x && self.y - self.height - 1 <= y && y <= self.y } }Special type
implAs defined in , They are all special characteristics .If you want to add a support
Broom::draw()Auxiliary method of , Then in a separateimplDefine it in the block :impl Broom { fn broomstick_range(&self) -> Range<i32> { self.y - self.height - 1 .. self.y } } impl Visible for Broom { fn draw(&self, canvas: &mut Canvas) { for y in self.broomstick_range() { ... } ... } ... }
9.2.1 - The default method
Standard library
WriteThe definition of a feature includes awrite_allDefault implementation of :trait Write { fn write(&mut self, buf: &[u8]) -> Result<usize>; fn flush(&mut self) -> Result<()>; fn write_all(&mut self, buf: &[u8]) -> Result<()> { let mut bytes_written = 0; while bytes_written < buf.len() { bytes_written += self.write(&buf[bytes_written..])?; } Ok(()) } ... }writeandflushMethod is the basic method that every writer must implement ;- The writer can also realize
write_all, without , Then the above default implementation will be used .
The most default methods in the standard library are
IteratorSpecial type , It has a necessary method (.next()) And many other default methods .
9.2.2 - Special type and other people's type
Rust It is allowed to implement any special type on any type , As long as the relevant features or types are imported into the current package .
Whenever you want to add a method to any type , Can use special type to complete :
trait IsEmoji { fn is_emoji(&self) -> bool; } /// Implement for built-in character types IsEmoji Method , This type is called extended type impl IsEmoji for char { fn is_emoji(&self) -> bool { ... } } assert_eq!('$'.is_emoji(), false);You can use generics
implblock , Let a type family realize an extended special type at one time .use std::io::{ self, Write}; /// You can send HTML The value of defines the extended type trait WriteHtml { fn write_html(&mut self, html: &HtmlDocument) -> io::Result<()>; } /// In this way, any std::io::writer write in HTML 了 // For each implementation Write The type of W, Here for W Then realize the special type WriteHtml impl<W: Write> WriteHtml for W { fn write_html(&mut self, html: &HtmlDocument) -> io::Result<()> { ... } }serdeFor all related types, a.serialize()Method :use serde::Serialize; use serde_json; pub fn save_configuration(config: &HashMap<String, String>) -> std::io::Result<()> { // Create a JSON Serialization handler , Write data to file let writer = File::create(config_filename())?; let mut serializer = serde_json::Serializer::new(writer); // The rest of the task is left to serde Of .serialize() Method treatment config.serialize(&mut serializer)?; Ok(()) }Coherence rule (coherence rule): When realizing the special type , The related features or types must be new in the current package . Ensure the uniqueness of the feature implementation .
9.2.3 - Special type Self
Special type can be used
SelfKeyword as type .pub trait Clone { fn clone(&self) -> Self; ... }SelfAs return type :x.clone()The type ofxThe type of .
The following features have two implementations :
pub trait Spliceable { fn splice(&self, other: &Self) -> Self } // self and other The type of must be exactly the same impl Spliceable for CherryTree { fn splice(&self, other: &Self) -> Self { // here Self yes CherryTree Another name for ... } } impl Spliceable for Mammoth { fn splice(&self, other: &Self) -> Self { // here Self yes Mammoth Another name for ... } }Use
SelfThe special type of type cannot coexist with the special target :// error : Special type Spliceable Cannot be a reference target fn splice_anything(left: &Spliceable, right: &Spliceable) { let combo = left.splice(right); ... }- Use special targets , The type can only be determined at runtime ;
- At compile time ,Rust Can't judge
leftandrightIs it the same type
Special goals can only be achieved for the simplest special types . This special type can be used Java The interface , perhaps C++ Abstract base class implementation in .
Special advanced special , Cannot coexist with special targets .
How to design a goal friendly feature :
pub trait MegaSpliceable { fn splice(&self, other: &MegaSpliceable) -> Box<MegaSpliceable>; } // call .splice() When the method is used ,other The type of parameter does not have to follow self The type is exactly the same // As long as both types are MegaSpliceable You can pass the type check
9.2.4 - Sub type
You can declare a special type as an extension of another special type
// All with roles Creature Relevant codes , You can also use the from Visible Special method trait Creature: Visible { fn position(&self) -> (i32, i32); fn facing(&self) -> Direction; ... }All implementation
CreatureThe type of , Must also be achievedVisibleSpecial type :impl Visible for Broom { ... } impl Creature for Broom { ... }Subtypes are similar Java or C# Word interface for , It is a special type. You need to use several other expressions to extend the existing special type .
9.2.5 - Static methods
Unlike other object-oriented languages ,Rust Special types can contain static methods and constructors .
trait StringSet { /// Returns a new empty set fn new() -> Self; /// Returns a containing strings A collection of all strings in fn from_slice(strings: &[&str]) -> Self; /// Determines whether the current collection contains a specific value fn contains(&self, string: &str) -> bool; /// Add a string to the current collection fn add(&mut self, string: &str); }All implementation
StringSetSpecial type , Must achieve this 4 Correlation functionsThe first two functions do not receive
selfParameters , They act as constructors . In non generic code , These functions can be used::Syntax call , Just like calling other static methods :// Create two implementations StringSet A set of hypothetical types let set1 = SortedStringSet::new(); let set2 = HashedStringSet::new();In generic code , The type is variable :
/// return document Not in wordlis A collection of words in fn unknown_words<S: StringSet>(document: &Vec<String>, wordlist: &S) -> S { let mut unknowns = S::new(); for word in document { if !wordlist.contains(word) { unknowns.add(word); } } unknowns }
Special targets do not support static methods : If you want to use special targets
&StringSet, You have to modify the special type , Addwhere Self: Sizedbinding .trait StringSet { fn new() -> Self where Self: Sized; fn from_slice(strings: &[&str]) -> Self where Self: Sized; fn contains(&self, string: &str) -> bool; fn add(&mut self, string: &str); }- tell Rust, Special targets will be exempt from supporting this static method .
- Use this way
&StringSetSpecial target , You can call.contains()and.add()Method .
9.3 - Fully qualified method calls
Method is actually a special function :
"hello".to_string() // Equivalent to str::to_string("hello")to_stringIt's a standard.ToStringSpecial method , The above code is equivalent to :ToString::to_string("hello") <str as ToString>::to_string("hello")Above 4 Method calls , Do the same :
- In general ,
value.method()This form is commonly used ; - Other forms are called qualified method calls :
- You need to specify the type or special type associated with the method
- The last form with angle brackets , At the same time, the associated type is specified , And special type , Therefore, it is called fully qualified method call .
- In general ,
Fully qualified method calls , Specify exactly the method to use , The application scenarios are :
Two methods have the same name
outlaw.draw(); // error ,.draw() Method contains outlaw Method Visible::draw(&outlaw); HasPistol::draw(&outlaw);It is impossible to infer
selfType of parameterlet zero = 0; // Type not specified zeor.abs(); // error , Can't find abs Method i64::abs(zero); // SureTake the function itself as a value
let words: Vec<String> = line.split_whitespace() // produce &str Value iterator .map(<str as ToString>::to_string) // Sure .collect();Call special methods in macros .
Fully qualified syntax also applies to static methods .
9.4 - Define the special type of type relationship
- A stereotype is a set of methods that a type can implement .
- Special types can be used to describe the relationship between types . There are the following 3 Ways of planting :
9.4.1 - Association type : How iterators work
std::iter::IteratorA type that generates values by itself , Associate different iterator types .iterator : Objects that can traverse a series of values through it .
pub trait Iterator { type Item; // Association type (associated type) fn next(&mut self) -> Option<Self::Item>; ... }All implementation
IteratorThe type of , Must specify their own items (item) The type of .Achieve one
IteratorThe type of :// std::env Part of the code of the standard library module impl Iterator for Args { type Item = String; // Type declaration fn next(&mut self) -> Option<String> { ... } ... }
Generic code can use association types :
/// Iterate over an iterator , Store their values in a new variable fn collect_into_vector<I: Iterator>(iter: I) -> Vec<I::Item> { let mut results = Vec::new(); for value in iter { results.push(value); } results }Association types are also commonly used when special types need to cover definitions other than one method :
In the library of a thread pool
TaskSpecial type ( Represents a unit of work ), Can contain an associatedOutputSpecial type ;One
PatternSpecial type ( A way to represent a search string ), Can contain an associatedMatchtype , Represents all the information collected after the pattern matches the string :trait Patern { type Match; fn search(&self, string: &str) -> Option<Self::Match>; } /// You can search for specific characters in the string impl Pattern for char { /// Match( matching ) Represents the position of the character found when type Match = usize; fn search(&self, string: &str) -> Option<usize> { ... } }A library that operates relational databases can have one
DatabaseConnectionSpecial type , There can be transactions 、 The pointer 、 Initialization statements and other related functions .
9.4.2 - Generic and special : The principle of operator overloading
std::ops::MulThe type of special association that can participate in multiplication ./// Support * The type of operator implements the special type pub trait Mul<RHS> { // RHS:Right Hand Side Right hand side /// application * The type result returned after the operator type Output; /// * Operator corresponding method fn mul(self, rhs: RHS) -> Self::Output; }- expression
lhs * rhsyesMul::mul(lhs, rhs)Abbreviation
- expression
9.4.3 - Companion type :rand::random working principle
randIt contains a special type related to random number generatorrand::Rng, It also contains a special type related to the type that can be randomly generatedrand::Rand.- Companion type : Special type for collaborative work .
9.5 - Reverse engineering binding
Like the following code :
use std::ops::{ Add, Mul}; fn dot<N>(v1: &[N], v2: &[N]) -> N where N: Add<Output=N> + Mul<Output=N> + Default + Copy // Yes N The binding of { let mut total = N::default(); for i in 0..v1.len() { total = total + v1[i] * v2[i]; } total } #[test] fn test_dot() { assert_eq!(dot(&[1, 2, 3, 4], &[1, 1, 1, 1]), 10); assert_eq!(dot(&[53.0, 7.0], &[1.0, 5.0]), 88.0); }Yes
NThe binding of is reverse engineered , Let the compiler be the guide , Double check your workNumberThe special type contains all operators and methods .Advantages of reverse engineering binding :
- You can make generic code forward compatible .
- Can guide the trouble to be solved through the compiler error .
- It exists in both code and documentation .
See 《Rust Programming 》( Jim - Brandy 、 Jason, - By orendov , Translated by lisongfeng ) Chapter 11
Original address
边栏推荐
- 单调栈-503. 下一个更大元素 II
- Unity learning notes
- Markdown learning
- [redis] redis persistent RDB vs AOF (source code)
- GIS实战应用案例100篇(七十八)-多规合一数据库设计及数据入库
- Gradle's method of dynamically modifying APK package name
- Get to know unity2 for the first time
- Golang's range
- Minimap plug-in
- Osgearth topographic shading map drawing
猜你喜欢

Three characteristics

Advanced OSG collision detection

Collection interface
![P1596 [USACO10OCT]Lake Counting S](/img/a7/07a84c93ee476788d9443c0add808b.png)
P1596 [USACO10OCT]Lake Counting S
![[cloud native] introduction and use of feign of microservices](/img/39/05cf7673155954c90e75a8a2eecd96.jpg)
[cloud native] introduction and use of feign of microservices

Image processing 8-cnn image classification

【云原生】微服务之Feign的介绍与使用

Use of ue5 QRcode plug-in

Introduction to hexadecimal coding

100 GIS practical application cases (78) - Multi compliance database design and data warehousing
随机推荐
【更新中】微信小程序学习笔记_3
Exe file running window embedding QT window
Clion toolchains are not configured configure disable profile problem solving
GIS实战应用案例100篇(七十八)-多规合一数据库设计及数据入库
796 · 开锁
[concurrent programming] Table hopping and blocking queue
Golang 字符串分割,替换和截取
详解sizeof、strlen、指针和数组等组合题
单调栈-503. 下一个更大元素 II
Kwai 20200412 recruitment
UE4 source code reading_ Bone model and animation system_ Animation compression
Pit & ADB wireless debugging of vivo real machine debugging
數據庫應用技術課程設計之商城管理系統
Talking about: is the HashSet set ordered or disordered /hashset set unique, why can we store elements with the same content
Animation_ IK overview
[cloud native] introduction and use of feign of microservices
Installation of PHP FPM software +openresty cache construction
Easy touch plug-in
Initial unity
Osganimation library parsing