impl Trait
impl Trait
与泛型类似。你还记得,泛型使用一个类型 T
(或任何其他名称),然后在程序编译时决定。首先我们来看一个具体的类型:
fn gives_higher_i32(one: i32, two: i32) { let higher = if one > two { one } else { two }; println!("{} is higher.", higher); } fn main() { gives_higher_i32(8, 10); }
这个打印:10 is higher.
.
但是这个只接受i32
,所以现在我们要把它做成通用的。我们需要比较,我们需要用{}
打印,所以我们的类型T需要PartialOrd
和Display
。记住,这意味着 "只接受已经实现PartialOrd
和Display
的类型"。
use std::fmt::Display; fn gives_higher_i32<T: PartialOrd + Display>(one: T, two: T) { let higher = if one > two { one } else { two }; println!("{} is higher.", higher); } fn main() { gives_higher_i32(8, 10); }
现在我们来看看impl Trait
,它也是类似的。我们可以引入一个类型 impl Trait
,而不是 T
。然后它将带入一个实现该特性的类型。这几乎是一样的。
fn prints_it(input: impl Into<String> + std::fmt::Display) { // Takes anything that can turn into a String and has Display println!("You can print many things, including {}", input); } fn main() { let name = "Tuon"; let string_name = String::from("Tuon"); prints_it(name); prints_it(string_name); }
然而,更有趣的是,我们可以返回 impl Trait
,这让我们可以返回闭包,因为它们的函数签名是trait。你可以在有它们的方法的签名中看到这一点。例如,这是 .map()
的签名。
#![allow(unused)] fn main() { fn map<B, F>(self, f: F) -> Map<Self, F> // 🚧 where Self: Sized, F: FnMut(Self::Item) -> B, { Map::new(self, f) } }
fn map<B, F>(self, f: F)
的意思是,它需要两个通用类型。F
是指从实现.map()
的容器中取一个元素的函数,B
是该函数的返回类型。然后在where
之后,我们看到的是trait bound。("trait bound"的意思是 "它必须有这个trait"。)一个是Sized
,接下来是闭包签名。它必须是一个 FnMut
,并在 Self::Item
上做闭包,也就是你给它的迭代器。然后它返回B
。
所以我们可以用同样的方法来返回一个闭包。要返回一个闭包,使用 impl
,然后是闭包签名。一旦你返回它,你就可以像使用一个函数一样使用它。下面是一个函数的小例子,它根据你输入的文本给出一个闭包。如果你输入 "double "或 "triple",那么它就会把它乘以2或3,否则就会返给你相同的数字。因为它是一个闭包,我们可以做任何我们想做的事情,所以我们也打印一条信息。
fn returns_a_closure(input: &str) -> impl FnMut(i32) -> i32 { match input { "double" => |mut number| { number *= 2; println!("Doubling number. Now it is {}", number); number }, "triple" => |mut number| { number *= 40; println!("Tripling number. Now it is {}", number); number }, _ => |number| { println!("Sorry, it's the same: {}.", number); number }, } } fn main() { let my_number = 10; // Make three closures let mut doubles = returns_a_closure("double"); let mut triples = returns_a_closure("triple"); let mut quadruples = returns_a_closure("quadruple"); doubles(my_number); triples(my_number); quadruples(my_number); }
下面是一个比较长的例子。让我们想象一下,在一个游戏中,你的角色面对的是晚上比较强的怪物。我们可以创建一个叫TimeOfDay
的枚举来记录一天的情况。你的角色叫西蒙,有一个叫character_fear
的数字,也就是f64
。它晚上上升,白天下降。我们将创建一个change_fear
函数,改变他的恐惧,但也做其他事情,如写消息。它大概是这样的:
enum TimeOfDay { // just a simple enum Dawn, Day, Sunset, Night, } fn change_fear(input: TimeOfDay) -> impl FnMut(f64) -> f64 { // The function takes a TimeOfDay. It returns a closure. // We use impl FnMut(64) -> f64 to say that it needs to // change the value, and also gives the same type back. use TimeOfDay::*; // So we only have to write Dawn, Day, Sunset, Night // Instead of TimeOfDay::Dawn, TimeOfDay::Day, etc. match input { Dawn => |x| { // This is the variable character_fear that we give it later println!("The morning sun has vanquished the horrible night. You no longer feel afraid."); println!("Your fear is now {}", x * 0.5); x * 0.5 }, Day => |x| { println!("What a nice day. Maybe put your feet up and rest a bit."); println!("Your fear is now {}", x * 0.2); x * 0.2 }, Sunset => |x| { println!("The sun is almost down! This is no good."); println!("Your fear is now {}", x * 1.4); x * 1.4 }, Night => |x| { println!("What a horrible night to have a curse."); println!("Your fear is now {}", x * 5.0); x * 5.0 }, } } fn main() { use TimeOfDay::*; let mut character_fear = 10.0; // Start Simon with 10 let mut daytime = change_fear(Day); // Make four closures here to call every time we want to change Simon's fear. let mut sunset = change_fear(Sunset); let mut night = change_fear(Night); let mut morning = change_fear(Dawn); character_fear = daytime(character_fear); // Call the closures on Simon's fear. They give a message and change the fear number. // In real life we would have a Character struct and use it as a method instead, // like this: character_fear.daytime() character_fear = sunset(character_fear); character_fear = night(character_fear); character_fear = morning(character_fear); }
这个打印:
What a nice day. Maybe put your feet up and rest a bit.
Your fear is now 2
The sun is almost down! This is no good.
Your fear is now 2.8
What a horrible night to have a curse.
Your fear is now 14
The morning sun has vanquished the horrible night. You no longer feel afraid.
Your fear is now 7