malongshuai / malongshuai.github.io

2 stars 0 forks source link

Rust入门秘籍(更新中) | 骏马金龙 #190

Open malongshuai opened 3 years ago

malongshuai commented 3 years ago

https://www.junmajinlong.com/rust/index/

Rust入门秘籍以书籍方式发布。 #—-> 链接:Rust入门秘籍 <—-#

Jasonwu123 commented 3 years ago

教练,我想学rust

youth7 commented 3 years ago

教练,我想学rust

Jancd commented 3 years ago

支持

homeword-wind commented 3 years ago

感谢博主的奉献,这书的质量真心高

homeword-wind commented 3 years ago

期待下一次更新,建议博主可以在其他平台多多推广,

bagualing commented 3 years ago

写得非常好,干货,没废话。期待更新,能完成全部章节内容。

quhxuxm commented 3 years ago

博主的书写得很好,内容讲的很深入,特别是那些解释“为什么这么做”的内容特别透彻是很多书籍里面没有提到的也没有说明白的,希望博主继续完成全部内容

malongshuai commented 3 years ago

@quhxuxm 博主的书写得很好,内容讲的很深入,特别是那些解释“为什么这么做”的内容特别透彻是很多书籍里面没有提到的也没有说明白的,希望博主继续完成全部内容

感谢支持。因为忙着自己的事,博客已经停更好几个月了。近期写了一些Rust异步和Tokio相关的成系列的文章,等完成了会发布上来。

lipish commented 2 years ago

真不错

ghost commented 2 years ago

非常不错的文章,谢谢。 结合rust官方的教程,非常有帮助。 确实句句是精华。

quhxuxm commented 2 years ago

很期待 “异步IO/fs/Stream/Frame” 这一节,特别是Frame这部分,如何正确使用Encoder/Decoder是我目前遇到的问题,比如Encoder里面如何处理网络io里面数据读完的情况

wlpy commented 2 years ago

不错的教程,受益匪浅,感谢作者。网站好像挂了,希望能修复一下

ghost commented 2 years ago

有关move,你讲的最清楚。

malongshuai commented 2 years ago

@hdilw16 有关move,你讲的最清楚。

个人以为,所有权问题本身是没有难度的,里面涉及到的只是一种种需要掌握的概念。我在学习所有权相关问题时,似乎没有遇到过理解不通透或者需要抓耳挠腮去理清楚的地方,学习的时候多数内容的逻辑都比较顺畅(当然,也有理解错误时候)。可能和个人学习经历有关,也可能是网上对它的宣传和解说加重了学习过程中的心理压力。

malongshuai commented 2 years ago

@quhxuxm 很期待 “异步IO/fs/Stream/Frame” 这一节,特别是Frame这部分,如何正确使用Encoder/Decoder是我目前遇到的问题,比如Encoder里面如何处理网络io里面数据读完的情况

抱歉。这部分的内容之前已经写的差不多了,但是需要找空闲时间去整理以及还需要少量内容的补充。我这几个月重度用了一段时间的tokio,有些用法且关键的地方在官方手册上并没有提及过,也需要去整理补充完善。但过去很长一段时间以及未来几个月可能还会处于忙碌期。

fortianwei commented 2 years ago

写的真的非常细致,感谢

MinsonLee commented 2 years ago

无意间发现博主写的《Rust入门秘籍》,太棒了~先打赏再看,哈哈哈

malongshuai commented 2 years ago

无意间发现博主写的《Rust入门秘籍》,太棒了~先打赏再看,哈哈哈

感谢,感谢支持哦

knull-cn commented 2 years ago

无意中发现了《Rust入门秘籍》,发现还是 junmajinlong 这个博主(之前看过ssl 等系列文章),顿时感觉质量有保障了。 暂时看了几个部分(match、类型),发现博主解决了我许多疑惑(比如,match 返回值),而许多其它的文章都语焉不详的。 感谢博主。已经打赏,聊表心意。

malongshuai commented 2 years ago

@knull-cn 感谢支持

Mota-Link commented 2 years ago

看到第6.2章,其中 “对于那些没有实现Clone Trait的自定义类型,需要手动实现Clone Trait。在自定义类型之前加上#[derive(Copy, Clone)]即可。” ,这里为什么不直接#[derive(Clone)]呢?根据我从其他地方学习到的:Copy是继承于Clone,所以实现Copy必须同时实现Clone。Clone似乎没有这样的限制,可以直接实现。

malongshuai commented 2 years ago

@Mota-Link 谢谢指正噢,刚才去看了下,确实多写了Copy进去。

gelove commented 2 years ago

6.4章可变引用那里应该是读写锁

knull-cn commented 2 years ago

建议添加下面几项:

  1. cargo.toml 专门的章节;因为, rust 多文件、多目录、多库自引用,引用第三方库等等,都跟 cargo.toml 有关
  2. 智能指针相关章节(比如 Box);感觉这个还是很有必要的,本身你的书中也多次提到、实践应用也比较多,而且也有助于理解内存、生命周期等(跟其它内存类型相互印证)。
  3. 宏定义:我觉得这个不是必须的,但是算 锦上添花
  4. 可以聊聊 对 C/C++ 库的引用——毕竟,Rust 相对而言出生不久,许多功能还不支持,而一般 C/C++ 都有这些库的支持,这些 C/C++ 遗产,用起来是很有必要、也很有需要的。
LIPUU commented 2 years ago

可能是讲tokio最清晰的一本中文书吧 条理清晰,读来醍醐灌顶

Mota-Link commented 2 years ago

@gelove 6.4章可变引用那里应该是读写锁

6.4章的功能应该是 None Lexical Lifetimes (NLL) ,详见RFC: https://github.com/rust-lang/rfcs/blob/master/text/2094-nll.md

gelove commented 2 years ago

@Mota-Link

@gelove 6.4章可变引用那里应该是读写锁

6.4章的功能应该是 None Lexical Lifetimes (NLL) ,详见RFC: https://github.com/rust-lang/rfcs/blob/master/text/2094-nll.md

他们也说了可以用锁来理解,我想这个锁应该是读写锁

gngshn commented 2 years ago

对于Trait A,写法dyn A表示Trait A的Trait Object类型,由于Trait Object的大小不固定,因此几乎总是使用Trait Object的引用方式&dyn A,Trait Object保存在栈中,包含两份数据:Trait Object所指向数据的指针和指向一个虚表vtable的指针。

这个说法感觉不太对, 存在栈上的是&dyn A, 是trait object的引用。trait object是DST不能存在栈上的。

malongshuai commented 2 years ago

对于Trait A,写法dyn A表示Trait A的Trait Object类型,由于Trait Object的大小不固定,因此几乎总是使用Trait Object的引用方式&dyn A,Trait Object保存在栈中,包含两份数据:Trait Object所指向数据的指针和指向一个虚表vtable的指针。

这个说法感觉不太对, 存在栈上的是&dyn A, 是trait object的引用。trait object是DST不能存在栈上的。

非常正确,感谢指正。

kaigedong commented 2 years ago

《再次理解Move》写的太好了,正是有这个疑问搜到的,感谢

oulaoba commented 2 years ago

https://rust-book.junmajinlong.com/ch100/06_task_state_sync.html 第二行代码好像是错了的 ,不应该是

let rwlock = Arc::new(Mutex::RwLock()); 

可能是

let rwlock  = Arc::new(RwLock::new(1));
malongshuai commented 2 years ago

https://rust-book.junmajinlong.com/ch100/06_task_state_sync.html 第二行代码好像是错了的 ,不应该是

let rwlock = Arc::new(Mutex::RwLock()); 

可能是

let rwlock  = Arc::new(RwLock::new(1));

谢谢,确实写错了

oulaoba commented 2 years ago

https://rust-book.junmajinlong.com/ch100/09_async_stream_sink_codec_framed.html

这里的sink 是个什么呀 ?有点摸不着头脑了。是怎么创建出来的呀?依赖于哪个包?能补上嘛 ?

malongshuai commented 2 years ago

https://rust-book.junmajinlong.com/ch100/09_async_stream_sink_codec_framed.html

这里的sink 是个什么呀 ?有点摸不着头脑了。是怎么创建出来的呀?依赖于哪个包?能补上嘛 ?

Stream和Sink一个是读,一个是写。类比一下,IO读read()、写write()都是直接读写字节的,但很多时候其实按字符串读写更直接简便:将读取的字节自动转换为字符串,或者将字符串自动转换为字节写入。这样可以省的手动去做重复的Bytes <-> String之间的转换。在这里,可以认为字符串是比Bytes让读写变得更简单的类型,也是对程序来说更有意义的数据类型,毕竟在程序里想要操作的是字符串。

类比于IO的读写,Stream的读和Sink的写,是对更有意义的数据的更简单的读写方式。当然也可以将想要读写的数据在YourDataType <-> Bytes之间进行手动的转换后再读写,但是复杂啰嗦且不必要。比如,使用Sink,可以直接将一个Struct类型的数据(当然要满足某些条件)写入TCP连接发送出去,不用转换为字节再发送,同理,通过Stream可以直接从TCP连接中读取字节数据并自动转换为想要的Struct类型。

其中,最常用的符合Stream读和Sink写的类型是Codec的Framed。Framed即实现了Sink,也实现了Stream。

至于你最后问的怎么创建出来、依赖于哪个包。

use futures_util::stream::{SplitSink, SplitStream};
use futures_util::{SinkExt, StreamExt};
use tokio::net::TcpStream;
use tokio_util::codec::{Framed, LinesCodec};

let conn = TcpStream::connect("127.0.0.1:12345").await.unwrap();
 // Framed既是Stream,也是Sink
// Stream用于读(Framed负责将底层字节转换为Frame,然后被Stream读取),
// Sink用于写(Framed负责将用户层的Frame转换为底层字节,然后写入Sink),
// StreamExt和SinkExt提供了相关的方便的方法
let framed = Framed::new(conn, LinesCodec::new());
let (mut sink, mut stream) = framed.split::<String>();

在你发的链接那篇文章的最开头有解释,Stream和Sink同时存在于futures、futures_util、futures_core这三个库里,这三个库这几个类型完全相同,追踪其本源,都来自于futures_core。当然,如果只用Stream,那么还可以使用tokio_stream。

Zolyn commented 2 years ago

https://rust-book.junmajinlong.com/ch6/03_ref_ownership_borrow.html
使用引用借用变量所有权时,【借完】之后会自动交还所有权,从而使得原变量不丢失所有权。至于什么时候【借完】,尚无法在此深究。

现在Rust有了NLL后,是否可以将【借完】的时机理解为引用作用域结束的时候?

Zolyn commented 2 years ago

https://rust-book.junmajinlong.com/ch6/05_re_understand_move.html

let user2 = &(*user);  // 不报错,解引用得到值后,对这个值创建引用,不会消耗值

这段代码实际上会报错,因为结构体User没有实现Deref Trrait,换一个例子是否更好?虽然知道这章想表达的点并不在这上,但可能会有人像我一样把这段代码复制粘贴到编辑器里看,结果发现只报了这一个错,把这行注释掉其他行才有报错,这可能会有点误导人(虽然最大的锅应该还是在rust编译器上)。

Zolyn commented 2 years ago

10.3章对枚举的解构应该是这样写的(漏加成员名了):

enum IPAddr {
  IPAddr4(u8,u8,u8,u8),
  IPAddr6(String),
}

fn main(){
  let ipv4 = IPAddr::IPAddr4(127,0,0,1);
  match ipv4 {
    // 丢弃解构后的第四个值
    IPAddr::IPAddr4(a,b,c,_) => println!("{},{},{}", a,b,c),
    IPAddr::IPAddr6(s) => println!("{}", s),
  }
}
malongshuai commented 2 years ago

10.3章对枚举的解构应该是这样写的(漏加成员名了):

enum IPAddr {
  IPAddr4(u8,u8,u8,u8),
  IPAddr6(String),
}

fn main(){
  let ipv4 = IPAddr::IPAddr4(127,0,0,1);
  match ipv4 {
    // 丢弃解构后的第四个值
    IPAddr::IPAddr4(a,b,c,_) => println!("{},{},{}", a,b,c),
    IPAddr::IPAddr6(s) => println!("{}", s),
  }
}

好的。感谢指正提醒,谢谢。

sirs05 commented 1 year ago

https://rust-book.junmajinlong.com/ch6/05_re_understand_move.html 感谢您的书,我在这个章节的最后一个代码块发现一个错误,let user2 = &(*user); 并不像代码中提示不报错,而是报 type User cannot be dereferenced,可能存在笔误

sirs05 commented 1 year ago

https://rust-book.junmajinlong.com/ch10/03_deconstruction.html 页面接近最下方的内容 解引用(deref)的所有权转移问题 连接失效啦

malongshuai commented 1 year ago

https://rust-book.junmajinlong.com/ch10/03_deconstruction.html 页面接近最下方的内容 解引用(deref)的所有权转移问题 连接失效啦

非常感谢你的细心和提醒。这个链接对应的是再次理解Move的最后一段,以前我写了一大段关于解引用的所有权相关问题,但是后来总结成了一句话放在这个最后一段中。

失效链接暂时无法去更新,抱歉。

malongshuai commented 1 year ago

https://rust-book.junmajinlong.com/ch6/05_re_understand_move.html 感谢您的书,我在这个章节的最后一个代码块发现一个错误,let user2 = &(*user); 并不像代码中提示不报错,而是报 type User cannot be dereferenced,可能存在笔误

关于这个代码片段里的问题,错在 user 不是引用类型,所以*user是错的,如果user是一个User的引用,那么&(*user)是无措的。

Canda15 commented 1 year ago

啥时候能录点0基础rust?现在网上能找到的视频门槛都太高了,全是照着文档念,根本没有说明rust中弄出这种新东西到底有什么好处。看了很多教程太劝退了。

malongshuai commented 1 year ago

啥时候能录点0基础rust?现在网上能找到的视频门槛都太高了,全是照着文档念,根本没有说明rust中弄出这种新东西到底有什么好处。看了很多教程太劝退了。

零基础本来就不适合学习Rust。如果完全没有编程语言基础,暂时放下Rust作为第一门语言会比较好。如果有其它语言的基础,学习熟悉Rust的语法和特性,熬过第一阶段,写个完整的程序,就会变得很好了。

rtpacks commented 1 year ago

博主的书简单易懂有深度,非常感谢博主关于Rust内存的介绍。

我想和博主讨论一下,是否可以在可变引用排他性的解释中,拓展“独占锁”的生成方式。

https://rust-book.junmajinlong.com/ch6/04_understand_mutable_ref.html

可以将可变引用看作是一把独占锁。在当前作用域内,从第一次使用可变引用开始创建这把独占锁,之后无论使用原始变量(即所有权拥有者)、可变引用还是不可变引用都会抢占这把独占锁,以保证只有一方可以访问数据,每次抢得独占锁后,都会将之前所有引用变量给锁住,使它们变成不可用状态。当离开当前作用域时,当前作用域内的所有独占锁都被释放。

fn main() {
  let mut x = Box::new(42); // 1

  // 创建x的不可变引用,出现x的独占锁
  let mut z = &x; // 2

  // 在考虑引用检查问题和生命周期问题时,循环结构for {} 和多个独立的大括号 {} 是等价的
  for i in 0..100 {
    // 使用z的不可变引用
    println!("{}", z); // 3

    // 抢占x的独占锁,使得z不再可用
    x = Box::new(i); // 4
    // 因此下面的代码会报错
    // println!("{}", z);

    // 虽然z不可用,但z自身可以被重新赋值,重新赋值将丢弃z之前对x的引用,
    // 注意这里使用了x的不可变引用,它会抢占x的独占锁,
    // 虽然这里z重新引用了x,但和赋值之前引用的x已经不一样,它是一个新的引用,
    // 并且z在这里抢占到了新的x独占锁,而赋值之前的x独占锁已经被代码行4抢占
    z = &x; // 5
  }
}

在上面解释中,我的理解是第一次使用变量的可变引用时,这个独占锁才会出现。但给出的这段复杂代码是一个不可变引用和变量重新赋值的形式,它也会出现报错。

我想这种情况下是不是将 “独占锁” 生成的时机改成 “第一次使用可变引用开始或变量被重新赋值创建” 会更好一点。

rust新学徒,请博主赐教 :)

malongshuai commented 1 year ago

@azin-cn 博主的书简单易懂有深度,非常感谢博主关于Rust内存的介绍。

我想和博主讨论一下,是否可以在可变引用排他性的解释中,拓展“独占锁”的生成方式。

https://rust-book.junmajinlong.com/ch6/04_understand_mutable_ref.html

可以将可变引用看作是一把独占锁。在当前作用域内,从第一次使用可变引用开始创建这把独占锁,之后无论使用原始变量(即所有权拥有者)、可变引用还是不可变引用都会抢占这把独占锁,以保证只有一方可以访问数据,每次抢得独占锁后,都会将之前所有引用变量给锁住,使它们变成不可用状态。当离开当前作用域时,当前作用域内的所有独占锁都被释放。

fn main() {
  let mut x = Box::new(42); // 1

  // 创建x的不可变引用,出现x的独占锁
  let mut z = &x; // 2

  // 在考虑引用检查问题和生命周期问题时,循环结构for {} 和多个独立的大括号 {} 是等价的
  for i in 0..100 {
    // 使用z的不可变引用
    println!("{}", z); // 3

    // 抢占x的独占锁,使得z不再可用
    x = Box::new(i); // 4
    // 因此下面的代码会报错
    // println!("{}", z);

    // 虽然z不可用,但z自身可以被重新赋值,重新赋值将丢弃z之前对x的引用,
    // 注意这里使用了x的不可变引用,它会抢占x的独占锁,
    // 虽然这里z重新引用了x,但和赋值之前引用的x已经不一样,它是一个新的引用,
    // 并且z在这里抢占到了新的x独占锁,而赋值之前的x独占锁已经被代码行4抢占
    z = &x; // 5
  }
}

在上面解释中,我的理解是第一次使用变量的可变引用时,这个独占锁才会出现。但给出的这段复杂代码是一个不可变引用和变量重新赋值的形式,它也会出现报错。

我想这种情况下是不是将 “独占锁” 生成的时机改成 “第一次使用可变引用开始或变量被重新赋值创建” 会更好一点。

rust新学徒,请博主赐教 :)

sorry,我写错了,你是对的。刚开始let mut z = &x;是不可变引用,还没有创建“独占锁”。

我也是新学徒。如果发现有什么错误或描述不清、解释不好的地方,尽可以提出来,我会改正以及尽量解惑。写了很久代码,有些基础性的东西反而记忆不深刻了。

zhengjiaw commented 1 year ago

请教下博主的mdbook 是如何能够在右侧显示大纲的,博主可以分享下么。我看了一遍文档没找到比较直接的方式。

malongshuai commented 1 year ago

请教下博主的mdbook 是如何能够在右侧显示大纲的,博主可以分享下么。我看了一遍文档没找到比较直接的方式。

右侧有标题目录吗,我的浏览器里都没有啊。我以前确实添加过生成目录的代码,但是后来发现就没有了,也就没管它了。我也忘记了是怎么搞的了,过去好久了。

zhengjiaw commented 1 year ago

是。我看你写的《Rust入门秘籍》 是有的。应该是book.toml 要设置啥,之前没找到,现在找到了一个模板: rust-by-practice/zh-CN/book.toml at master · sunface/rust-by-practice (github.com) https://github.com/sunface/rust-by-practice/blob/master/zh-CN/book.toml [image: image.png]

masuai @.***> 于2023年10月22日周日 19:13写道:

请教下博主的mdbook 是如何能够在右侧显示大纲的,博主可以分享下么。我看了一遍文档没找到比较直接的方式。

右侧有标题目录吗,我的浏览器里都没有啊。我以前确实添加过生成目录的代码,但是后来发现就没有了,也就没管它了。我也忘记了是怎么搞的了,过去好久了。

— Reply to this email directly, view it on GitHub https://github.com/malongshuai/malongshuai.github.io/issues/190#issuecomment-1774065221, or unsubscribe https://github.com/notifications/unsubscribe-auth/AUZYF4TWNSWYXZYX3VOZU7LYAT5W5AVCNFSM4VSZVGJKU5DIOJSWCZC7NNSXTN2JONZXKZKDN5WW2ZLOOQ5TCNZXGQYDMNJSGIYQ . You are receiving this because you commented.Message ID: @.***>

fredgit commented 6 months ago

太感谢了,感觉很有帮助,觉得的确对知识点写得很详细,比如刚好搜到内存相关的讲解。知识点资料太多,能找到遇到适合自己能容易接受的,太不容易了。作者辛苦了