编辑回复: 👍
作者回复: 谢谢!github 上的已经更新到 clap 3 正式版本了
作者回复: 非常棒!你似乎是第一个贴出来思考题答案的!我也更新了一下代码库,和你的代码基本一样你可以对比一下。两个点:1. print_syntect 可以再加一个参数 ext,这样灵活性更高;2. 打印时用 print! 效果更好一些。
作者回复: 👍
作者回复: 有同学反应不能编译通过,问题出在 clap 上。请升级到 Rust 1.54 重新编译。 另外,reqwest 默认的 TLS 使用的是系统的 openssl,对于某些 linux 用户如果没有安装好 openssl,可能会导致编译不过,对此,你可以修改 Cargo.toml: ```toml reqwest = { version = "0.11", default-features = false, features = ["json", "rustls-tls"] } # HTTP 客户端 ``` 让 reqwest 使用 rustls。
作者回复: 好建议!
作者回复: 注意看 Colorize trait 的定义,它的方法 consume 的都是 self,而非 &self。所以当 impl Colorize for &str 时,self = &str。 在调用方法时,编译器会先看数据结构是否有对应的方法,如果有,按照方法的 signature,传 self / &self / &mut self。如果没有,再看引入的 trait 是否有对应的方法,必要时会根据 self 的类型做 auto Deref。所以这里编译器可以找到 blue(),因为它第一个参数 self = &str,String 可以 Deref 到 &str,所以可以调用。但如果 Colorize 的方法使用 &self,此时 &self = &&str,String 无法 Deref 到 &&str,所以编译器报错。 你可以看这个小例子: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=dbd526df998fc8701ea9855c9e7de73c ```rust pub trait Foo { fn foo(self); } pub trait Bar { fn bar(&self); } pub trait Baz { fn baz(&self); } impl Foo for &str { fn foo(self) { println!("Foo: {}", self); } } impl Bar for &str { fn bar(&self) { println!("Bar: {}", self); } } impl Baz for str { fn baz(&self) { println!("Baz: {}", self); } } fn main() { let s = String::from("Tyr"); // foo 第一个参数是 self = &str,String 可以 auto Deref 到 &str,所以可以调用 s.foo(); // bar 第一个参数是 &self = &&str,String 无法 auto Deref 到 &&str // s.bar(); // baz 第一个参数是 &self,但因为 impl Baz for str {}, 所以 &self = &str // 和 foo 类似,可以调用 s.baz(); } ```
作者回复: 继承的概念,在 Rust 里是没有的。而且我们要避免使用这样的思维去建模。很多时候我们提到继承,其实并不是想用继承,而是想通过继承使用多态。在 Rust 下我们可以通过泛型,trait,trait object 实现面向对象语言中主要的多态手段。 封装在任何编程语言中都或多或少存在,它本质上是一种对复杂性的控制。Rust 下 struct / enum / mod 都提供了封装的能力。把若干数据放在某个结构下,若干函数放在摸个模块下,只暴露该暴露的信息出去,这就是封装。 方法可以理解为第一个参数为 self/this 这样的指向调用者自己的特殊函数,在 Python、Javascript 都有类似的概念。Rust 下可以为数据结构 impl 方法,或者 impl trait 来实现接口的方法。注意 Rust 下的方法可以消费 self(第一个参数是 self 而非 &self),其它大多数语言只能消费 &self。
作者回复: 谢谢!