< 返回版块

chuqingq 发表于 2021-09-30 01:58

https://doc.rust-lang.org/src/std/fs.rs.html#614

impl Read for File {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.inner.read(buf)
    }

https://doc.rust-lang.org/src/std/fs.rs.html#660

impl Read for &File {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.inner.read(buf)
    }

疑问:先不关注两者实现相同,这两种实现时是什么关系?我理解file.read()都应该调用到第一个吧?

评论区

写评论
lan 2021-10-04 15:12

嗯,这是一个原因。

--
👇
NaokiLH: 所以原因是File的特殊性是吗

Bai-Jinlin 2021-10-03 17:10

我也很存疑,一般有个impl<R: Read + ?Sized> Read for &mut R 自然&mut File就能用了,而且也比较符合这个Trait的设计规格,体现出IO是有副作用需要mut的这一概念,对于Write也是,但是实际上为&File实现Read并没有什么问题,因为file的设计写入是通过的libc进行的,不需要file本身是mut,自然签名&mut &File也就没什么问题,但是总是感觉哪里不对劲。

NaokiLH 2021-10-03 13:55

所以原因是File的特殊性是吗

--
👇
yuikonnu: 国庆快乐!我再补充一下吧。

对于impl<'a> Read for &'a FileRead::read的签名应当是fn read<'b>(self: &'b mut &'a File, ...) -> ...。这是非常自然的,对T(这里是&'a File)实现Read,那Read::read的参数&mut self就是&mut T,没有任何特殊性。

看起来拿到一个&mut &T没有什么意义,因为解引用也只能得到一个&T,是不可变的。但这里特殊的东西是File,它背后是操作系统的文件,可以看做其具有内部可变性且线程安全,拿到&File就能够执行“读取”操作而不用担心其内部的状态因共享被破坏。

但标准库为读取设计的Trait Read中的一些方法默认了实现者需要拿到独占借用&mut T,可我们知道对于File只需要&File就够了,所以标准库在这样特殊的情况下,为&File实现了Read(以及其它文件操作的Traits)。最终我们看到了一个奇怪的&mut &File,它的前半部分&mut源自Read::read(以及其它函数)的签名,后半部分出现了&File(而不是预期的&mut File)是因为操作系统为File解决了原本Rust区分&mut T&T想解决的问题。

即使标准库不为&File实现Read,我们也可以用Arc<Mutex<File>>达到相同的目的,但这损失了效率。

lan 2021-10-01 00:36

国庆快乐!我再补充一下吧。

对于impl<'a> Read for &'a FileRead::read的签名应当是fn read<'b>(self: &'b mut &'a File, ...) -> ...。这是非常自然的,对T(这里是&'a File)实现Read,那Read::read的参数&mut self就是&mut T,没有任何特殊性。

看起来拿到一个&mut &T没有什么意义,因为解引用也只能得到一个&T,是不可变的。但这里特殊的东西是File,它背后是操作系统的文件,可以看做其具有内部可变性且线程安全,拿到&File就能够执行“读取”操作而不用担心其内部的状态因共享被破坏。

但标准库为读取设计的Trait Read中的一些方法默认了实现者需要拿到独占借用&mut T,可我们知道对于File只需要&File就够了,所以标准库在这样特殊的情况下,为&File实现了Read(以及其它文件操作的Traits)。最终我们看到了一个奇怪的&mut &File,它的前半部分&mut源自Read::read(以及其它函数)的签名,后半部分出现了&File(而不是预期的&mut File)是因为操作系统为File解决了原本Rust区分&mut T&T想解决的问题。

即使标准库不为&File实现Read,我们也可以用Arc<Mutex<File>>达到相同的目的,但这损失了效率。

作者 chuqingq 2021-09-30 22:27

谢谢!我先贴下您的说明:

// &mut 的意思是,获取独占引用(你可以利用这个指针修改值,也可以不修改;而且你修改值必须通过独占引用)
// 而 read 方法实际并没有修改值,也就意味着,这个 read 方法只是获取了共享引用 Foo 的独占引用。
// 这没有违法借用规则,因为对于 Foo ,只存在共享引用,没有独占引用。程序通过编译。

// 当你去掉上面的代码注释,意味着你通过共享引用 Foo 的独占引用修改 Foo 的数据,这违反了借用规则:
// 因为对于 Foo 意味着至少一个共享引用存在的同时,还存在一个独占引用(就是修改值的那个指针),
// 所以这时程序不会通过编译:
// cannot assign to `self.a`, which is behind a `&` reference

然后说下我的理解:

怎么说呢,我觉得既然能编译过去,就肯定有办法去解释。但是rust的这个逻辑不是很简洁,或者过于复杂,很难让人直观的理解。

当你去掉上面的代码注释,意味着你通过共享引用 Foo 的独占引用修改 Foo 的数据,这违反了借用规则: 因为对于 Foo 意味着至少一个共享引用存在的同时,还存在一个独占引用(就是修改值的那个指针),

按照直观逻辑,能进入到fn read(&mut self, ...),就应该已经获取到了对Foo的所谓独占引用,而不是在调用self.a = 10;时才触发编译错误。

我比较认同 @yuikonnu 的解释:

read接收一个&mut &MyStruct。这里的&mut &应当只是为了满足Read::read的签名。

我可以认为:在这种情况下,fn read(&mut self, ...)的&mut self其实就是为了满足read的签名,是个“假的”。

--
👇
苦瓜小仔: 对于 &mut &self 的回答:

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=a5b5f90902cc82f53494e812324bdc36

--
👇
chuqingq: 谢谢解答!

我没有说清楚,我的意思是trait Readread方法对receiver的要求是&mut

对于问题2,我还是觉得别扭。

我认为trait Readfn read&mut self应该就是表达这个意思:需要一个可变引用作为receiver,在read方法中可以修改。

但是下面这个例子如果注掉self.a = 10;这行,可以编译通过,去注释就不能编译通过。这是不是说明read的&mut self其实是个“假的”?

use std::io::Read;

#[derive(Debug)]
struct Foo {
    a: i32,
}

impl Foo {
    fn write(&mut self) {
        self.a = 20;                                                                                                        }
}

impl Read for &Foo {
    fn read(&mut self, _buf: &mut [u8]) -> std::io::Result<usize> {
        self.a = 10;
        Ok(0)
    }
}

fn main() {                                                                                                                 
    let f = Foo{a: 1};
    // bar(&f);
}

MyStruct在read中修改自身,理所当然的要看read的receiver是&self还是&mut self,但竟然还要看impl Read for的是&MyStruct还是&mut MyStruct,而且竟竟然还和read的实现有关,read中要真的改了self,又编译不过。这个怎么说也有点惊奇啊

--
👇
苦瓜小仔: > trait Read 本身要求 receiver 是 &mut

这句话错了。trait 并不会要求其方法内的任何参数是哪种引用/所有权形式,所以你要看具体的方法签名。

Read / Write 的大部分方法签名的确使用了 &mut self ,但是也有使用 &self 的啊。所以为什么没有理由不通过呢?反过来说,如果因为有 &mut self 的方法就拒绝编译这个 trait impl,那么这意味着不允许含 &self 的方法在 shared reference 时使用,你觉得对吗?

任何事物都有两面性,有多强大就有多复杂。这的确很复杂,但是这完全不是重点。 重点是,你学习/理解了一种写法/用法,并且能在将来的场景中模仿/应用实现 (implmentation)。

--
👇
chuqingq: 谢谢! 其实我关注的不是std::fs::File,当成是某个自定义struct吧,MyStruct。 对于我前面的问题1,我纠结的是,trait Read本身要求receiver是&mut,且对于MyStruct来说,impl Read for MyStruct还不够,还需要impl Read for &MyStruct,甚至还需要impl Read for &mut MyStruct,这样是不是有点太复杂了?

对于问题2,因为trait Read本身要求receiver是&mut,如果只是impl Read for &MyStruct,而不是impl Read for &mut MyStruct,是不是应该编译不通过?

--
👇
yuikonnu: 1. 这不是一个Common的情况,许多Trait都有类似impl<'_, T: Trait> Trait for &'_ T 的实现; 2. 文件的状态由操作系统维护,不是File

可以看看这个问题(及其duplicate)的回答:https://stackoverflow.com/questions/60140539/why-is-the-write-trait-implemented-for-file-and-tcpstream-is-it-safe

--
👇
chuqingq: 这里又引申出来两个问题:

  1. impl Trait for &Type确实可以为调用方解决bar(&f)传递引用,而无需move的问题,但是实现方每次都要搞两套实现,违背了DRY原则

  2. 这里传递的&f,从语义上来说应该是不可变引用,但是却可以通过f.read()实际改变自己

请问是不是存在这样的问题?

苦瓜小仔 2021-09-30 16:51

对于 &mut &self 的回答:

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=a5b5f90902cc82f53494e812324bdc36

--
👇
chuqingq: 谢谢解答!

我没有说清楚,我的意思是trait Readread方法对receiver的要求是&mut

对于问题2,我还是觉得别扭。

我认为trait Readfn read&mut self应该就是表达这个意思:需要一个可变引用作为receiver,在read方法中可以修改。

但是下面这个例子如果注掉self.a = 10;这行,可以编译通过,去注释就不能编译通过。这是不是说明read的&mut self其实是个“假的”?

use std::io::Read;

#[derive(Debug)]
struct Foo {
    a: i32,
}

impl Foo {
    fn write(&mut self) {
        self.a = 20;                                                                                                        }
}

impl Read for &Foo {
    fn read(&mut self, _buf: &mut [u8]) -> std::io::Result<usize> {
        self.a = 10;
        Ok(0)
    }
}

fn main() {                                                                                                                 
    let f = Foo{a: 1};
    // bar(&f);
}

MyStruct在read中修改自身,理所当然的要看read的receiver是&self还是&mut self,但竟然还要看impl Read for的是&MyStruct还是&mut MyStruct,而且竟竟然还和read的实现有关,read中要真的改了self,又编译不过。这个怎么说也有点惊奇啊

--
👇
苦瓜小仔: > trait Read 本身要求 receiver 是 &mut

这句话错了。trait 并不会要求其方法内的任何参数是哪种引用/所有权形式,所以你要看具体的方法签名。

Read / Write 的大部分方法签名的确使用了 &mut self ,但是也有使用 &self 的啊。所以为什么没有理由不通过呢?反过来说,如果因为有 &mut self 的方法就拒绝编译这个 trait impl,那么这意味着不允许含 &self 的方法在 shared reference 时使用,你觉得对吗?

任何事物都有两面性,有多强大就有多复杂。这的确很复杂,但是这完全不是重点。 重点是,你学习/理解了一种写法/用法,并且能在将来的场景中模仿/应用实现 (implmentation)。

--
👇
chuqingq: 谢谢! 其实我关注的不是std::fs::File,当成是某个自定义struct吧,MyStruct。 对于我前面的问题1,我纠结的是,trait Read本身要求receiver是&mut,且对于MyStruct来说,impl Read for MyStruct还不够,还需要impl Read for &MyStruct,甚至还需要impl Read for &mut MyStruct,这样是不是有点太复杂了?

对于问题2,因为trait Read本身要求receiver是&mut,如果只是impl Read for &MyStruct,而不是impl Read for &mut MyStruct,是不是应该编译不通过?

--
👇
yuikonnu: 1. 这不是一个Common的情况,许多Trait都有类似impl<'_, T: Trait> Trait for &'_ T 的实现; 2. 文件的状态由操作系统维护,不是File

可以看看这个问题(及其duplicate)的回答:https://stackoverflow.com/questions/60140539/why-is-the-write-trait-implemented-for-file-and-tcpstream-is-it-safe

--
👇
chuqingq: 这里又引申出来两个问题:

  1. impl Trait for &Type确实可以为调用方解决bar(&f)传递引用,而无需move的问题,但是实现方每次都要搞两套实现,违背了DRY原则

  2. 这里传递的&f,从语义上来说应该是不可变引用,但是却可以通过f.read()实际改变自己

请问是不是存在这样的问题?

作者 chuqingq 2021-09-30 16:13

明白了,谢谢解答!

--
👇
yuikonnu: 对于1:

如果这个MyStruct是你自己实现的,而不是对某种资源的封装,那么实现Read势必需要改变自身内部的状态。那么impl<'_> Read for &'_ MyStruct是没有意义的。而impl Read for &mut MyStruct不需要你实现,Read的设计者已经为你实现了

「这不是一个Common的情况」包含两点,一是Read在多数情况下伴随状态的改变,所以在这个Trait的实现中不能为&T添加一个泛型的实现;二是File刚好作为特殊的一份子,它是对操作系统资源的封装,而操作系统早已考虑到多线程读写的情况,它像AtomicI32这样的原子类型一样可以随意“可变地”共享。多数情况下这两个条件不会同时满足。

对于2:

我没有太懂你的意思,在impl<'a> Read for &'a MyStruct 的环境下,read接收一个&mut &MyStruct。这里的&mut &应当只是为了满足Read::read的签名。

--
👇
chuqingq: 谢谢! 其实我关注的不是std::fs::File,当成是某个自定义struct吧,MyStruct。 对于我前面的问题1,我纠结的是,trait Read本身要求receiver是&mut,且对于MyStruct来说,impl Read for MyStruct还不够,还需要impl Read for &MyStruct,甚至还需要impl Read for &mut MyStruct,这样是不是有点太复杂了?

对于问题2,因为trait Read本身要求receiver是&mut,如果只是impl Read for &MyStruct,而不是impl Read for &mut MyStruct,是不是应该编译不通过?

作者 chuqingq 2021-09-30 16:01

谢谢解答!

我没有说清楚,我的意思是trait Readread方法对receiver的要求是&mut

对于问题2,我还是觉得别扭。

我认为trait Readfn read&mut self应该就是表达这个意思:需要一个可变引用作为receiver,在read方法中可以修改。

但是下面这个例子如果注掉self.a = 10;这行,可以编译通过,去注释就不能编译通过。这是不是说明read的&mut self其实是个“假的”?

use std::io::Read;

#[derive(Debug)]
struct Foo {
    a: i32,
}

impl Foo {
    fn write(&mut self) {
        self.a = 20;                                                                                                        }
}

impl Read for &Foo {
    fn read(&mut self, _buf: &mut [u8]) -> std::io::Result<usize> {
        self.a = 10;
        Ok(0)
    }
}

fn main() {                                                                                                                 
    let f = Foo{a: 1};
    // bar(&f);
}

MyStruct在read中修改自身,理所当然的要看read的receiver是&self还是&mut self,但竟然还要看impl Read for的是&MyStruct还是&mut MyStruct,而且竟竟然还和read的实现有关,read中要真的改了self,又编译不过。这个怎么说也有点惊奇啊

--
👇
苦瓜小仔: > trait Read 本身要求 receiver 是 &mut

这句话错了。trait 并不会要求其方法内的任何参数是哪种引用/所有权形式,所以你要看具体的方法签名。

Read / Write 的大部分方法签名的确使用了 &mut self ,但是也有使用 &self 的啊。所以为什么没有理由不通过呢?反过来说,如果因为有 &mut self 的方法就拒绝编译这个 trait impl,那么这意味着不允许含 &self 的方法在 shared reference 时使用,你觉得对吗?

任何事物都有两面性,有多强大就有多复杂。这的确很复杂,但是这完全不是重点。 重点是,你学习/理解了一种写法/用法,并且能在将来的场景中模仿/应用实现 (implmentation)。

--
👇
chuqingq: 谢谢! 其实我关注的不是std::fs::File,当成是某个自定义struct吧,MyStruct。 对于我前面的问题1,我纠结的是,trait Read本身要求receiver是&mut,且对于MyStruct来说,impl Read for MyStruct还不够,还需要impl Read for &MyStruct,甚至还需要impl Read for &mut MyStruct,这样是不是有点太复杂了?

对于问题2,因为trait Read本身要求receiver是&mut,如果只是impl Read for &MyStruct,而不是impl Read for &mut MyStruct,是不是应该编译不通过?

--
👇
yuikonnu: 1. 这不是一个Common的情况,许多Trait都有类似impl<'_, T: Trait> Trait for &'_ T 的实现; 2. 文件的状态由操作系统维护,不是File

可以看看这个问题(及其duplicate)的回答:https://stackoverflow.com/questions/60140539/why-is-the-write-trait-implemented-for-file-and-tcpstream-is-it-safe

--
👇
chuqingq: 这里又引申出来两个问题:

  1. impl Trait for &Type确实可以为调用方解决bar(&f)传递引用,而无需move的问题,但是实现方每次都要搞两套实现,违背了DRY原则

  2. 这里传递的&f,从语义上来说应该是不可变引用,但是却可以通过f.read()实际改变自己

请问是不是存在这样的问题?

lan 2021-09-30 15:02

对于1:

如果这个MyStruct是你自己实现的,而不是对某种资源的封装,那么实现Read势必需要改变自身内部的状态。那么impl<'_> Read for &'_ MyStruct是没有意义的。而impl Read for &mut MyStruct不需要你实现,Read的设计者已经为你实现了

「这不是一个Common的情况」包含两点,一是Read在多数情况下伴随状态的改变,所以在这个Trait的实现中不能为&T添加一个泛型的实现;二是File刚好作为特殊的一份子,它是对操作系统资源的封装,而操作系统早已考虑到多线程读写的情况,它像AtomicI32这样的原子类型一样可以随意“可变地”共享。多数情况下这两个条件不会同时满足。

对于2:

我没有太懂你的意思,在impl<'a> Read for &'a MyStruct 的环境下,read接收一个&mut &MyStruct。这里的&mut &应当只是为了满足Read::read的签名。

--
👇
chuqingq: 谢谢! 其实我关注的不是std::fs::File,当成是某个自定义struct吧,MyStruct。 对于我前面的问题1,我纠结的是,trait Read本身要求receiver是&mut,且对于MyStruct来说,impl Read for MyStruct还不够,还需要impl Read for &MyStruct,甚至还需要impl Read for &mut MyStruct,这样是不是有点太复杂了?

对于问题2,因为trait Read本身要求receiver是&mut,如果只是impl Read for &MyStruct,而不是impl Read for &mut MyStruct,是不是应该编译不通过?

苦瓜小仔 2021-09-30 14:47

trait Read 本身要求 receiver 是 &mut

这句话错了。trait 并不会要求其方法内的任何参数是哪种引用/所有权形式,所以你要看具体的方法签名。

Read / Write 的大部分方法签名的确使用了 &mut self ,但是也有使用 &self 的啊。所以为什么没有理由不通过呢?反过来说,如果因为有 &mut self 的方法就拒绝编译这个 trait impl,那么这意味着不允许含 &self 的方法在 shared reference 时使用,你觉得对吗?

任何事物都有两面性,有多强大就有多复杂。这的确很复杂,但是这完全不是重点。 重点是,你学习/理解了一种写法/用法,并且能在将来的场景中模仿/应用实现 (implmentation)。

--
👇
chuqingq: 谢谢! 其实我关注的不是std::fs::File,当成是某个自定义struct吧,MyStruct。 对于我前面的问题1,我纠结的是,trait Read本身要求receiver是&mut,且对于MyStruct来说,impl Read for MyStruct还不够,还需要impl Read for &MyStruct,甚至还需要impl Read for &mut MyStruct,这样是不是有点太复杂了?

对于问题2,因为trait Read本身要求receiver是&mut,如果只是impl Read for &MyStruct,而不是impl Read for &mut MyStruct,是不是应该编译不通过?

--
👇
yuikonnu: 1. 这不是一个Common的情况,许多Trait都有类似impl<'_, T: Trait> Trait for &'_ T 的实现; 2. 文件的状态由操作系统维护,不是File

可以看看这个问题(及其duplicate)的回答:https://stackoverflow.com/questions/60140539/why-is-the-write-trait-implemented-for-file-and-tcpstream-is-it-safe

--
👇
chuqingq: 这里又引申出来两个问题:

  1. impl Trait for &Type确实可以为调用方解决bar(&f)传递引用,而无需move的问题,但是实现方每次都要搞两套实现,违背了DRY原则

  2. 这里传递的&f,从语义上来说应该是不可变引用,但是却可以通过f.read()实际改变自己

请问是不是存在这样的问题?

作者 chuqingq 2021-09-30 14:09

谢谢! 其实我关注的不是std::fs::File,当成是某个自定义struct吧,MyStruct。 对于我前面的问题1,我纠结的是,trait Read本身要求receiver是&mut,且对于MyStruct来说,impl Read for MyStruct还不够,还需要impl Read for &MyStruct,甚至还需要impl Read for &mut MyStruct,这样是不是有点太复杂了?

对于问题2,因为trait Read本身要求receiver是&mut,如果只是impl Read for &MyStruct,而不是impl Read for &mut MyStruct,是不是应该编译不通过?

--
👇
yuikonnu: 1. 这不是一个Common的情况,许多Trait都有类似impl<'_, T: Trait> Trait for &'_ T 的实现; 2. 文件的状态由操作系统维护,不是File

可以看看这个问题(及其duplicate)的回答:https://stackoverflow.com/questions/60140539/why-is-the-write-trait-implemented-for-file-and-tcpstream-is-it-safe

--
👇
chuqingq: 这里又引申出来两个问题:

  1. impl Trait for &Type确实可以为调用方解决bar(&f)传递引用,而无需move的问题,但是实现方每次都要搞两套实现,违背了DRY原则

  2. 这里传递的&f,从语义上来说应该是不可变引用,但是却可以通过f.read()实际改变自己

请问是不是存在这样的问题?

lan 2021-09-30 13:36
  1. 这不是一个Common的情况,许多Trait都有类似impl<'_, T: Trait> Trait for &'_ T 的实现;
  2. 文件的状态由操作系统维护,不是File

可以看看这个问题(及其duplicate)的回答:https://stackoverflow.com/questions/60140539/why-is-the-write-trait-implemented-for-file-and-tcpstream-is-it-safe

--
👇
chuqingq: 这里又引申出来两个问题:

  1. impl Trait for &Type确实可以为调用方解决bar(&f)传递引用,而无需move的问题,但是实现方每次都要搞两套实现,违背了DRY原则

  2. 这里传递的&f,从语义上来说应该是不可变引用,但是却可以通过f.read()实际改变自己

请问是不是存在这样的问题?

作者 chuqingq 2021-09-30 11:22

这里又引申出来两个问题:

  1. impl Trait for &Type确实可以为调用方解决bar(&f)传递引用,而无需move的问题,但是实现方每次都要搞两套实现,违背了DRY原则

  2. 这里传递的&f,从语义上来说应该是不可变引用,但是却可以通过f.read()实际改变自己

请问是不是存在这样的问题?

作者 chuqingq 2021-09-30 10:57

明白了,谢谢谢谢!

--
👇
Bai-Jinlin: 就是假如你这个函数参数是impl Read的话,而且File没有实现impl Read for &File你就只能传所有权进去

--
👇
chuqingq: 谢谢!没看明白,有没有具体的例子?或者官方文档哪里有讲,帮给个链接?

--
👇
Bai-Jinlin: 范型会用上,作为范型参数不会自动引用,没有第二个的话你就只能传File了

作者 chuqingq 2021-09-30 10:57

明白了,非常感谢!

--
👇
Grobycn: ``` use std::io::Read;

#[derive(Debug)] struct Foo;

impl Read for Foo { fn read(&mut self, buf: &mut [u8]) -> std::io::Result { Ok(0) } }

fn bar<T: Read>(r: T) {}

fn main() { let f = Foo; // bar(&f); the trait std::io::Read is not implemented for &Foo bar(f); // println!("{:?}", f); borrow of moved value: f }


--  
👇  
chuqingq: 谢谢!没看明白,有没有具体的例子?或者官方文档哪里有讲,帮给个链接?

--  
👇  
Bai-Jinlin: 范型会用上,作为范型参数不会自动引用,没有第二个的话你就只能传File了


Bai-Jinlin 2021-09-30 09:48

就是假如你这个函数参数是impl Read的话,而且File没有实现impl Read for &File你就只能传所有权进去

--
👇
chuqingq: 谢谢!没看明白,有没有具体的例子?或者官方文档哪里有讲,帮给个链接?

--
👇
Bai-Jinlin: 范型会用上,作为范型参数不会自动引用,没有第二个的话你就只能传File了

Grobycn 2021-09-30 09:14
use std::io::Read;

#[derive(Debug)]
struct Foo;

impl Read for Foo {
    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
        Ok(0)
    }
}

fn bar<T: Read>(r: T) {}

fn main() {
    let f = Foo;
    // bar(&f); the trait `std::io::Read` is not implemented for `&Foo`
    bar(f);
    // println!("{:?}", f); borrow of moved value: `f`
}

--
👇
chuqingq: 谢谢!没看明白,有没有具体的例子?或者官方文档哪里有讲,帮给个链接?

--
👇
Bai-Jinlin: 范型会用上,作为范型参数不会自动引用,没有第二个的话你就只能传File了

作者 chuqingq 2021-09-30 08:41

谢谢!没看明白,有没有具体的例子?或者官方文档哪里有讲,帮给个链接?

--
👇
Bai-Jinlin: 范型会用上,作为范型参数不会自动引用,没有第二个的话你就只能传File了

Bai-Jinlin 2021-09-30 06:55

范型会用上,作为范型参数不会自动引用,没有第二个的话你就只能传File了

1 共 19 条评论, 1 页