于2022年10月21日2022年10月21日由Sukuna发布
13-1
返回一个Option枚举值,如果时间小于24,就返回Option<i32>,如果大于24,就是不对的值,要返回None.这一题教我们如何返回Option类型的值
fn maybe_icecream(time_of_day: u16) -> Option<u16> {
// We use the 24-hour system here, so 10PM is a value of 22
// The Option output should gracefully handle cases where time_of_day > 24.
if time_of_day > 24{
None
}
else if time_of_day > 12{
Some(0)
}
else{
Some(5)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn check_icecream() {
assert_eq!(maybe_icecream(9), Some(5));
assert_eq!(maybe_icecream(10), Some(5));
assert_eq!(maybe_icecream(23), Some(0));
assert_eq!(maybe_icecream(22), Some(0));
assert_eq!(maybe_icecream(25), None);
}
#[test]
fn raw_value() {
// TODO: Fix this test. How do you get at the value contained in the Option?
let icecreams = maybe_icecream(12);
assert_eq!(icecreams, Some(5));
}
}
13-2
这一题需要我们了解if-let和while-let的用法,if-let和while-let的核心用法就是匹配.
if let Some(i) = 一个Option<T>值,当匹配的时候,产生一个新的变量i并且执行下面的操作.while-let也是如此
核心的思想就是Some(i) = 一个Option值,然后这样可以巧妙地提取Option的内容并且避免冗杂的match表达式
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn simple_option() {
let target = "rustlings";
let optional_target = Some(target);
// TODO: Make this an if let statement whose value is "Some" type
if let Some(word) = optional_target{
assert_eq!(word, target);
}
}
#[test]
fn layered_option() {
let mut range = 10;
let mut optional_integers: Vec<Option<i8>> = Vec::new();
for i in 0..(range + 1) {
optional_integers.push(Some(i));
}
// TODO: make this a while let statement - remember that vector.pop also adds another layer of Option<T>
// You can stack `Option<T>`'s into while let and if let
while let Some(Some(integer)) = optional_integers.pop() {
assert_eq!(integer, range);
range -= 1;
}
}
}
13-3
struct Point {
x: i32,
y: i32,
}
fn main() {
let y: Option<Point> = Some(Point { x: 100, y: 200 });
match y {
Some(ref p) => println!("Co-ordinates are {},{} ", p.x, p.y),
_ => println!("no match"),
}
y; // Fix without deleting this line.
}
再取Option里面的结构体的时候,我们需要知道,结构体在option里面,所有权是归Option值的,后面又访问了一次Option值,所以说y还没有放弃所有权,只能通过引用去访问.(y没有放弃所有权,里面的结构体也是属于y的,y= Some(p)来取数据是不对的)
14-1
Vec是一个带有泛型(参数是类型)类型的结构,我们声明的时候需要添加泛型参数.
fn main() {
let mut shopping_list: Vec<?> = Vec::new();
shopping_list.push("milk");
}
?替换成String就好,因为需要声明为Vec<String>,因为Vec<String>是类型但是Vec<>不是类型.
14-2
将这个代码改成泛型,记住函数、结构体、impl块的泛型类型
struct Wrapper<T> {
value: T,
}
impl<T> Wrapper<T> {
pub fn new(value: T) -> Self {
Wrapper { value }
}
}
15-1
完成代码,完成AppendBar这个trait,注意trait块里面的接口的返回值有可能是Self类型的,代表和本身是一个类型的.
trait AppendBar {
fn append_bar(self) -> Self;
}
impl AppendBar for String {
//Add your code here
fn append_bar(mut self) -> String{
self.push_str("Bar");
self
}
}
fn main() {
let s = String::from("Foo");
let s = s.append_bar();
println!("s: {}", s);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn is_foo_bar() {
assert_eq!(String::from("Foo").append_bar(), String::from("FooBar"));
}
#[test]
fn is_bar_bar() {
assert_eq!(
String::from("").append_bar().append_bar(),
String::from("BarBar")
);
}
}
15-2
trait AppendBar {
fn append_bar(self) -> Self;
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn is_vec_pop_eq_bar() {
let mut foo = vec![String::from("Foo")].append_bar();
assert_eq!(foo.pop().unwrap(), String::from("Bar"));
assert_eq!(foo.pop().unwrap(), String::from("Foo"));
}
}
从题目中我们可以知道是要给Vec<String>实现AppendBar这个trait,语法和上面一样
impl AppendBar for Vec<String>{
fn append_bar(mut self) -> Vec<String>{
self.push("Bar".to_string());
self
}
}
15-3
这一题需要我们修改trait里面方法的默认实现模式
改成这样:
pub trait Licensed {
pub trait Licensed {
fn licensing_info(&self) -> String{
"Some information".to_string()
}
}
struct SomeSoftware {
version_number: i32,
}
struct OtherSoftware {
version_number: String,
}
impl Licensed for SomeSoftware {} // Don't edit this line
impl Licensed for OtherSoftware {} // Don't edit this line
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn is_licensing_info_the_same() {
let licensing_info = String::from("Some information");
let some_software = SomeSoftware { version_number: 1 };
let other_software = OtherSoftware {
version_number: "v2.0.0".to_string(),
};
assert_eq!(some_software.licensing_info(), licensing_info);
assert_eq!(other_software.licensing_info(), licensing_info);
}
}
15-4
这里需要我们用trait和泛型配合,使得函数的传参只能传已经实现某种trait的结构体
pub trait Licensed {
fn licensing_info(&self) -> String {
"some information".to_string()
}
}
struct SomeSoftware {}
struct OtherSoftware {}
impl Licensed for SomeSoftware {}
impl Licensed for OtherSoftware {}
// YOU MAY ONLY CHANGE THE NEXT LINE
fn compare_license_types(software: ??, software_two: ??) -> bool {
software.licensing_info() == software_two.licensing_info()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn compare_license_information() {
let some_software = SomeSoftware {};
let other_software = OtherSoftware {};
assert!(compare_license_types(some_software, other_software));
}
#[test]
fn compare_license_information_backwards() {
let some_software = SomeSoftware {};
let other_software = OtherSoftware {};
assert!(compare_license_types(other_software, some_software));
}
}
把函数签名改成fn compare_license_types<T : Licensed,E : Licensed>(software: T, software_two: E) -> bool
就好
15-5
这里需要我们再15-4的基础上再进一步,函数的传参只能传已经实现多种trait的结构体.
// traits5.rs
//
// Your task is to replace the '??' sections so the code compiles.
// Don't change any line other than the marked one.
// Execute `rustlings hint traits5` or use the `hint` watch subcommand for a hint.
// I AM NOT DONE
pub trait SomeTrait {
fn some_function(&self) -> bool {
true
}
}
pub trait OtherTrait {
fn other_function(&self) -> bool {
true
}
}
struct SomeStruct {}
struct OtherStruct {}
impl SomeTrait for SomeStruct {}
impl OtherTrait for SomeStruct {}
impl SomeTrait for OtherStruct {}
impl OtherTrait for OtherStruct {}
// YOU MAY ONLY CHANGE THE NEXT LINE
fn some_func(item: ??) -> bool {
item.some_function() && item.other_function()
}
fn main() {
some_func(SomeStruct {});
some_func(OtherStruct {});
}
改成这样就好
16-1
assert!(表达式),如果表达式为true还好,表达式为false就panic
#[cfg(test)]
mod tests {
#[test]
fn you_can_assert() {
assert!(1 < 2);
}
}
16-2
asserteq!(A,B),A=B是没事,反之panic
#[cfg(test)]
mod tests {
#[test]
fn you_can_assert_eq() {
assert_eq!(1,1);
}
}
16-3
自己编写test,挺简单的.
17-1
fn longest(x: &str, y: &str) -> &str {
if x.len() > y.len() {
x
} else {
y
}
}
fn main() {
let string1 = String::from("abcd");
let string2 = "xyz";
let result = longest(string1.as_str(), string2);
println!("The longest string is '{}'", result);
}
书本里的例子,作为函数要去判断传参和返回的引用符不符合生命周期的标准,也就是说传参的生命周期要和返回的生命周期匹配并且满足可以省略的要求,如果不满足可以省略的要求就需要标注生命周期标注
不满足隐藏的条件显示声明生命周期,统一成一样的.即fn longest<'a>(x: &'a str, y: &'a str) -> &'a str
17-2
基于17-1,因为’a作为生命周期泛型,匹配传参中生命周期最短的生命周期,然后把这个生命周期返回出去,但是返回出去的生命周期不能支撑result.
fn main() {
let string1 = String::from("long string is long");
let result;
{
let string2 = String::from("xyz");
result = longest(string1.as_str(), string2.as_str());
}
println!("The longest string is '{}'", result);
}
改成这样:
fn main() {
let string1 = String::from("long string is long");
{
let string2 = String::from("xyz");
let result = longest(string1.as_str(), string2.as_str());
println!("The longest string is '{}'", result);
}
}
17-3
结构体里面有引用,则需要保证结构体里面引用成员的生命周期要比结构体长.
所以说要配一个泛型参数,指定结构体的生命周期是所有引用成员里面最小的那个即可.这就是泛型参数的作用
struct Book {
author: &str,
title: &str,
}
fn main() {
let name = String::from("Jill Smith");
let title = String::from("Fish Flying");
let book = Book { author: &name, title: &title };
println!("{} by {}", book.title, book.author);
}
生命周期是需要在类型后面加上’xxx的,注意一下’xxx的语法
struct Book<'a> {
author: &'a str,
title: &'a str,
}
fn main() {
let name = String::from("Jill Smith");
let title = String::from("Fish Flying");
let book = Book { author: &name, title: &title };
println!("{} by {}", book.title, book.author);
}