Merge pull request #245 from Tanish-Eagle/editing

Editing
This commit is contained in:
Sunface 2022-06-30 09:50:45 +08:00 committed by GitHub
commit 908a3bb0c0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 83 additions and 83 deletions

View File

@ -9,7 +9,7 @@ pub trait CacheableItem: Clone + Default + fmt::Debug + Decodable + Encodable {
}
```
Using of `Address` is much more clearable and convenient than `AsRef<[u8]> + Clone + fmt::Debug + Eq + Hash`.
Using of `Address` is much more clearer and convenient than `AsRef<[u8]> + Clone + fmt::Debug + Eq + Hash`.
1. 🌟🌟🌟
```rust,editable
@ -89,7 +89,7 @@ fn main() {
assert_eq!(Point { x: 2, y: 3 } - Point { x: 1, y: 0 },
Point { x: 1, y: 3 });
println!("Success!")
println!("Success!");
}
```
@ -110,7 +110,7 @@ trait AgeWidget {
fn get(&self) -> u8;
}
// A form with both a UsernameWidget and an AgeWidget
// A form with both a UsernameWidget and an AgeWidget.
struct Form {
username: String,
age: u8,
@ -141,10 +141,10 @@ fn main() {
let username = UsernameWidget::get(&form);
assert_eq!("rustacean".to_owned(), username);
let age = AgeWidget::get(&form); // you can also use `<Form as AgeWidget>::get`
let age = AgeWidget::get(&form); // You can also use `<Form as AgeWidget>::get`
assert_eq!(28, age);
println!("Success!")
println!("Success!");
}
```
@ -187,7 +187,7 @@ fn main() {
assert_eq!(__, "*waving arms furiously*");
println!("Success!")
println!("Success!");
}
```
@ -253,7 +253,7 @@ fn main() {
## Orphan Rules
We can’t implement external traits on external types. For example, we can’t implement the `Display` trait on `Vec<T>` within our own crate, because `Display` and `Vec<T>` are defined in the standard library and aren’t local to our crate.
This restriction is often called as the orphan rule, so named because the parent type is not present. This rule ensures that other people’s code can’t break your code and vice versa.
This restriction is often called the orphan rule, so named because the parent type is not present. This rule ensures that other people’s code can’t break your code and vice versa.
It’s possible to get around this restriction using the newtype pattern, which involves creating a new type in a tuple struct.

View File

@ -25,15 +25,15 @@ impl<T: Debug, const N: usize> Debug for ArrayPair<T, N> {
fn foo<const N: usize>() {}
fn bar<T, const M: usize>() {
foo::<M>(); // ok: `M` is a const parameter
foo::<2021>(); // ok: `2021` is a literal
foo::<{20 * 100 + 20 * 10 + 1}>(); // ok: const expression contains no generic parameters
foo::<M>(); // Okay: `M` is a const parameter
foo::<2021>(); // Okay: `2021` is a literal
foo::<{20 * 100 + 20 * 10 + 1}>(); // Okay: const expression contains no generic parameters
foo::<{ M + 1 }>(); // error: const expression contains the generic parameter `M`
foo::<{ std::mem::size_of::<T>() }>(); // error: const expression contains the generic parameter `T`
foo::<{ M + 1 }>(); // Error: const expression contains the generic parameter `M`
foo::<{ std::mem::size_of::<T>() }>(); // Error: const expression contains the generic parameter `T`
let _: [u8; M]; // ok: `M` is a const parameter
let _: [u8; std::mem::size_of::<T>()]; // error: const expression contains the generic parameter `T`
let _: [u8; M]; // Okay: `M` is a const parameter
let _: [u8; std::mem::size_of::<T>()]; // Error: const expression contains the generic parameter `T`
}
fn main() {}
@ -89,14 +89,14 @@ fn main() {
}
];
println!("Success!")
println!("Success!");
}
```
2. 🌟🌟
```rust,editable
// fill in the blanks to make it work
// Fill in the blanks to make it work.
fn print_array<__>(__) {
println!("{:?}", arr);
}
@ -109,7 +109,7 @@ fn main() {
}
```
3. 🌟🌟🌟 Sometimes we want to limit the size of an variable, e.g when using in embedding evironments, then `const expressions` will fit your need.
3. 🌟🌟🌟 Sometimes we want to limit the size of a variable, e.g when using in embedding environments, then `const expressions` will fit your needs.
```rust,editable
#![allow(incomplete_features)]
@ -122,15 +122,15 @@ where
//...
}
// fix the errors in main
// Fix the errors in main.
fn main() {
check_size([0u8; 767]);
check_size([0i32; 191]);
check_size(["helloδ½ ε₯½"; __]); // size of &str ?
check_size(["helloδ½ ε₯½".to_string(); __]); // size of String?
check_size(['δΈ­'; __]); // size of char ?
check_size(["helloδ½ ε₯½"; __]); // Size of &str ?
check_size(["helloδ½ ε₯½".to_string(); __]); // Size of String?
check_size(['δΈ­'; __]); // Size of char ?
println!("Success!")
println!("Success!");
}

View File

@ -4,7 +4,7 @@
1. 🌟🌟🌟
```rust,editable
// fill in the blanks to make it work
// Fill in the blanks to make it work
struct A; // Concrete type `A`.
struct S(A); // Concrete type `S`.
struct SGen<T>(T); // Generic type `SGen`.
@ -29,14 +29,14 @@ fn main() {
// Implicitly specified type parameter `char` to `generic()`.
generic(__);
println!("Success!")
println!("Success!");
}
```
2. 🌟🌟 A function call with explicitly specified type parameters looks like: `fun::<A, B, ...>()`.
```rust,editable
// implement the generic function below
// Implement the generic function below.
fn sum
fn main() {
@ -44,7 +44,7 @@ fn main() {
assert_eq!(50, sum(20, 30));
assert_eq!(2.46, sum(1.23, 1.23));
println!("Success!")
println!("Success!");
}
```
@ -54,38 +54,38 @@ fn main() {
3. 🌟
```rust,editable
// implement struct Point to make it work
// Implement struct Point to make it work.
fn main() {
let integer = Point { x: 5, y: 10 };
let float = Point { x: 1.0, y: 4.0 };
println!("Success!")
println!("Success!");
}
```
4. 🌟🌟
```rust,editable
// modify this struct to make the code work
// Modify this struct to make the code work
struct Point<T> {
x: T,
y: T,
}
fn main() {
// DON'T modify here
// DON'T modify this code.
let p = Point{x: 5, y : "hello".to_string()};
println!("Success!")
println!("Success!");
}
```
5. 🌟🌟
```rust,editable
// add generic for Val to make the code work, DON'T modify the code in `main`
// Add generic for Val to make the code work, DON'T modify the code in `main`.
struct Val {
val: f64,
}
@ -114,7 +114,7 @@ struct Point<T, U> {
}
impl<T, U> Point<T, U> {
// implement mixup to make it work, DON'T modify other code
// Implement mixup to make it work, DON'T modify other code.
fn mixup
}
@ -127,14 +127,14 @@ fn main() {
assert_eq!(p3.x, 5);
assert_eq!(p3.y, 'δΈ­');
println!("Success!")
println!("Success!");
}
```
7. 🌟🌟
```rust,editable
// fix the errors to make the code work
// Fix the errors to make the code work.
struct Point<T> {
x: T,
y: T,
@ -148,7 +148,7 @@ impl Point<f32> {
fn main() {
let p = Point{x: 5, y: 10};
println!("{}",p.distance_from_origin())
println!("{}",p.distance_from_origin());
}
```

View File

@ -4,7 +4,7 @@ In [traits chapter](https://practice.rs/generics-traits/traits.html#returning-ty
Also one limitation of arrays is that they can only store elements of one type, yeah, enum is a not bad solution when our items are a fixed set of types in compile time, but trait object are more flexible and powerful here.
## Returning Traits with dyn
The Rust compiler needs to know how much space a function's return type requires. Because the different implementations of a trait probably will need different amounts of memoery, this means function need to return a concrete type or the same type when using `impl Trait`, or it can return a trait object with `dyn`.
The Rust compiler needs to know how much space a function's return type requires. Because the different implementations of a trait probably will need different amounts of memory, this means function need to return a concrete type or the same type when using `impl Trait`, or it can return a trait object with `dyn`.
1. 🌟🌟🌟
```rust,editable
@ -39,26 +39,26 @@ impl Bird for Swan {
}
fn main() {
// FILL in the blank
// FILL in the blank.
let duck = __;
duck.swim();
let bird = hatch_a_bird(2);
// this bird has forgotten how to swim, so below line will cause an error
// This bird has forgotten how to swim, so below line will cause an error.
// bird.swim();
// but it can quak
// But it can quak.
assert_eq!(bird.quack(), "duck duck");
let bird = hatch_a_bird(1);
// this bird has forgotten how to fly, so below line will cause an error
// This bird has forgotten how to fly, so below line will cause an error.
// bird.fly();
// but it can quak too
// But it can quak too.
assert_eq!(bird.quack(), "swan swan");
println!("Success!")
println!("Success!");
}
// IMPLEMENT this function
// IMPLEMENT this function.
fn hatch_a_bird...
```
@ -95,13 +95,13 @@ impl Bird for Swan {
}
fn main() {
// FILL in the blank to make the code work
// FILL in the blank to make the code work.
let birds __;
for bird in birds {
bird.quack();
// when duck and swan turns into Bird, they all forgot how to fly, only remeber how to quack
// so, the below code will cause an error
// When duck and swan turn into Birds, they all forgot how to fly, only remember how to quack.
// So, the code below will cause an error.
// bird.fly();
}
}
@ -113,7 +113,7 @@ fn main() {
3. 🌟🌟
```rust,editable
// FILL in the blanks
// FILL in the blanks.
trait Draw {
fn draw(&self) -> String;
}
@ -134,13 +134,13 @@ fn main() {
let x = 1.1f64;
let y = 8u8;
// draw x
// Draw x.
draw_with_box(__);
// draw y
// Draw y.
draw_with_ref(&y);
println!("Success!")
println!("Success!");
}
fn draw_with_box(x: Box<dyn Draw>) {
@ -153,11 +153,11 @@ fn draw_with_ref(x: __) {
```
## Static and Dynamic dispatch
when we use trait bounds on generics: the compiler generates nongeneric implementations of functions and methods for each concrete type that we use in place of a generic type parameter. The code that results from monomorphization is doing static dispatch, which is when the compiler knows what method you’re calling at compile time.
When we use trait bounds on generics, the compiler generates nongeneric implementations of functions and methods for each concrete type that we use in place of a generic type parameter. The code that results from monomorphization is doing static dispatch, which is when the compiler knows what method you’re calling at compile time.
When we use trait objects, Rust must use dynamic dispatch. The compiler doesn’t know all the types that might be used with the code that is using trait objects, so it doesn’t know which method implemented on which type to call. Instead, at runtime, Rust uses the pointers inside the trait object to know which method to call. There is a runtime cost when this lookup happens that doesn’t occur with static dispatch. Dynamic dispatch also prevents the compiler from choosing to inline a method’s code, which in turn prevents some optimizations.
However, we did get extra flexibility when using dynamic dispatch.
However, we do get extra flexibility when using dynamic dispatch.
4. 🌟🌟
```rust,editable
@ -174,10 +174,10 @@ impl Foo for String {
fn method(&self) -> String { format!("string: {}", *self) }
}
// IMPLEMENT below with generics
// IMPLEMENT below with generics.
fn static_dispatch...
// implement below with trait objects
// Implement below with trait objects.
fn dynamic_dispatch...
fn main() {
@ -187,7 +187,7 @@ fn main() {
static_dispatch(x);
dynamic_dispatch(&y);
println!("Success!")
println!("Success!");
}
```
@ -200,8 +200,8 @@ You can only make object-safe traits into trait objects. A trait is object safe
5. 🌟🌟🌟🌟
```rust,editable
// Use at least two approaches to make it work
// DON'T add/remove any code line
// Use at least two approaches to make it work.
// DON'T add/remove any code line.
trait MyTrait {
fn f(&self) -> Self;
}
@ -222,7 +222,7 @@ fn main() {
my_function(Box::new(13_u32));
my_function(Box::new(String::from("abc")));
println!("Success!")
println!("Success!");
}
```

View File

@ -81,8 +81,8 @@ fn main() {
1. 🌟🌟
```rust,editable
// fill in the two impl blocks to make the code work
// DON'T modify the code in `main`
// Fill in the two impl blocks to make the code work.
// DON'T modify the code in `main`.
trait Hello {
fn say_hi(&self) -> String {
String::from("hi")
@ -107,7 +107,7 @@ fn main() {
assert_eq!(t.say_hi(), "Hi, I'm your new teacher");
assert_eq!(t.say_something(), "I'm not a bad teacher");
println!("Success!")
println!("Success!");
}
```
@ -135,7 +135,7 @@ impl Inches {
}
// ADD some attributes to make the code work!
// DON'T modify other codes!
// DON'T modify other code!
struct Seconds(i32);
fn main() {
@ -171,23 +171,23 @@ In Rust, many of the operators can be overloaded via traits. That is, some opera
use std::ops;
// implement fn multiply to make the code work
// As mentiond above, `+` needs `T` to implement `std::ops::Add` Trait
// so, what about `*` ? You can find the answer here: https://doc.rust-lang.org/core/ops/
// Implement fn multiply to make the code work.
// As mentiond above, `+` needs `T` to implement `std::ops::Add` Trait.
// So, what about `*`? You can find the answer here: https://doc.rust-lang.org/core/ops/
fn multipl
fn main() {
assert_eq!(6, multiply(2u8, 3u8));
assert_eq!(5.0, multiply(1.0, 5.0));
println!("Success!")
println!("Success!");
}
```
4. 🌟🌟🌟
```rust,editable
// fix the errors, DON'T modify the code in `main`
// Fix the errors, DON'T modify the code in `main`.
use std::ops;
struct Foo;
@ -217,12 +217,12 @@ impl ops::Sub<Foo> for Bar {
}
fn main() {
// DON'T modify the below code
// you need to derive some trait for FooBar to make it comparable
// DON'T modify the code below.
// You need to derive some trait for FooBar to make it comparable.
assert_eq!(Foo + Bar, FooBar);
assert_eq!(Foo - Bar, BarFoo);
println!("Success!")
println!("Success!");
}
```
@ -232,8 +232,8 @@ Instead of a concrete type for the item parameter, we specify the impl keyword a
5. 🌟🌟🌟
```rust,editable
// implement `fn summary` to make the code work
// fix the errors without removing any code line
// Implement `fn summary` to make the code work.
// Fix the errors without removing any code line
trait Summary {
fn summarize(&self) -> String;
}
@ -281,14 +281,14 @@ fn main() {
println!("{:?}", weibo);
}
// implement `fn summary` below
// Implement `fn summary` below.
```
### Returning Types that Implement Traits
We can also use the impl Trait syntax in the return position to return a value of some type that implements a trait.
However, you can only use impl Trait if you’re returning a single type, using Trait Objects instead when you really need to return serveral types.
However, you can only use impl Trait if you’re returning a single type, use Trait Objects instead when you really need to return several types.
6. 🌟🌟
```rust,editable
@ -313,7 +313,7 @@ impl Animal for Cow {
}
// Returns some struct that implements Animal, but we don't know which one at compile time.
// FIX the erros here, you can make a fake random, or you can use trait object
// FIX the errors here, you can make a fake random, or you can use trait object.
fn random_animal(random_number: f64) -> impl Animal {
if random_number < 0.5 {
Sheep {}
@ -340,7 +340,7 @@ fn main() {
assert_eq!(sum(1, 2), 3);
}
// implement `fn sum` with trait bound in two ways
// Implement `fn sum` with trait bound in two ways.
fn sum<T>(x: T, y: T) -> T {
x + y
}
@ -348,7 +348,7 @@ fn sum<T>(x: T, y: T) -> T {
8. 🌟🌟
```rust,editable
// FIX the errors
// FIX the errors.
struct Pair<T> {
x: T,
y: T,
@ -388,10 +388,10 @@ fn main() {
9. 🌟🌟🌟
```rust,editable
// fill in the blanks to make it work
// Fill in the blanks to make it work
fn example1() {
// `T: Trait` is the commonly used way
// `T: Fn(u32) -> u32` specifies that we can only pass a closure to `T`
// `T: Trait` is the commonly used way.
// `T: Fn(u32) -> u32` specifies that we can only pass a closure to `T`.
struct Cacher<T: Fn(u32) -> u32> {
calculation: T,
value: Option<u32>,
@ -424,7 +424,7 @@ fn example1() {
fn example2() {
// We can also use `where` to constrain `T`
// We can also use `where` to construct `T`
struct Cacher<T>
where T: Fn(u32) -> u32,
{
@ -465,7 +465,7 @@ fn main() {
example1();
example2();
println!("Success!")
println!("Success!");
}
```