< 返回版块

NenX 发表于 2024-11-08 14:00

Tags:我是一名 Rust 新手,学习 Rust 的时候遇到这个问题:为什么 value_ref2 不加类型会导致编译失败呢?

// 可以编译通过

fn main(){

    let mut value = 1u8;

    let value_ref1 = &mut value;

    let value_ref2: &mut u8 = value_ref1;

    *value_ref2 = 99;

    println!("value is {}",value_ref1);

}
// 编译失败

fn main(){

    let mut value = 1u8;

    let value_ref1 = &mut value;

    let value_ref2 = value_ref1;

    *value_ref2 = 99;

    println!("value is {}",value_ref1);

}

评论区

写评论
SleepyBoy 2024-11-18 12:36

确实是这样。但是IDE里rr其实已经分析出来实际的推导类型,感觉编译器还有待更新啊😂

--
👇
gjh7754: 猜测是如果泛型Trait有多个泛型参数类型的实现时,则在函数调用时,编译器无法准确的推断函数入参类型,从而无法自动再借用。 而MyFrom只有一个泛型参数类型的实现,所以可以推断出函数入参类型为可变引用,从而自动进行了再借用。如果像楼下所说的再给MyFrom加一个不同泛型参数类型的实现就会出现From相同的问题。 而本文中From虽然只有一个实现,但是在std标准库里,From有一个通用的实现是涵盖所有类型的,所以编译器的类型推断就出问题了。

impl<T> From<T> for T { 
    /// Returns the argument unchanged. 
    #[inline(always)] 
    fn from(t: T) -> T { 
        t 
    }
}

如果像下面这样指定泛型参数类型后,编译器就可以自动再借用了

fn _fail(p: &mut I) {
    let _x11 = <S as From<&mut I>>::from(p);
    let _x12 = S::from(p); 
}

--
👇
LazyBoy: 还有有疑问没搞懂,为什么相同的两个Trait写法,标准库的From就不行,是有什么其他隐含规则吗

gjh7754 2024-11-15 16:22

猜测是如果泛型Trait有多个泛型参数类型的实现时,则在函数调用时,编译器无法准确的推断函数入参类型,从而无法自动再借用。 而MyFrom只有一个泛型参数类型的实现,所以可以推断出函数入参类型为可变引用,从而自动进行了再借用。如果像楼下所说的再给MyFrom加一个不同泛型参数类型的实现就会出现From相同的问题。 而本文中From虽然只有一个实现,但是在std标准库里,From有一个通用的实现是涵盖所有类型的,所以编译器的类型推断就出问题了。

impl<T> From<T> for T { 
    /// Returns the argument unchanged. 
    #[inline(always)] 
    fn from(t: T) -> T { 
        t 
    }
}

如果像下面这样指定泛型参数类型后,编译器就可以自动再借用了

fn _fail(p: &mut I) {
    let _x11 = <S as From<&mut I>>::from(p);
    let _x12 = S::from(p); 
}

--
👇
LazyBoy: 还有有疑问没搞懂,为什么相同的两个Trait写法,标准库的From就不行,是有什么其他隐含规则吗

TinusgragLin 2024-11-08 19:48

还有有疑问没搞懂,为什么相同的两个Trait写法,标准库的From就不行,是有什么其他隐含规则吗

看起来编译器耍了一个小聪明:S::my_from 事实上只有一种可能。如果你给 S::my_from 再加个实现:

impl MyFrom<usize> for S {
    fn my_from(p: usize) -> S {
        S
    }
}

就会出现一样的错误。我的猜测是,编译器在进行重借用时,类型推断可能还没完全做完。

SleepyBoy 2024-11-08 17:48

还有有疑问没搞懂,为什么相同的两个Trait写法,标准库的From就不行,是有什么其他隐含规则吗

struct I(i32);
struct S;

trait MyFrom<T> : Sized {
    /// Converts to this type from the input type.
    #[must_use]
    fn my_from(p: T) -> Self;
}

impl From<&mut I> for S {
    fn from(p: &mut I) -> S {
        p.0 = 2;
        S
    }
}
impl MyFrom<&mut I> for S {
    fn my_from(p: &mut I) -> S {
        p.0 = 2;
        S
    }
}

fn _ok(p: &mut I) {
    let _x11 = S::my_from(p);
    let _x12 = S::my_from(p); // 正常
}

fn _fail(p: &mut I) {
    let _x11 = S::from(p);
    // consider creating a fresh reborrow of `p` here: `&mut *`
    let _x12 = S::from(p); // 错误,"use of moved value: `p`"
}

--
👇
dakai-chen: 站内有一个相关文章:https://rustcc.cn/article?id=f983986d-de03-44c5-a0d0-277a4e170c4f

dakai-chen 2024-11-08 14:35

站内有一个相关文章:https://rustcc.cn/article?id=f983986d-de03-44c5-a0d0-277a4e170c4f

dakai-chen 2024-11-08 14:33
let value_ref2: &mut u8 = value_ref1; // 这个写法发生了重借用,而不是移动变量
let value_ref2 = &mut *value_ref1; // 类似这种写法
1 共 6 条评论, 1 页