< 返回版块

hzqd 发表于 2021-03-19 22:56

第一段代码:

use std::any::type_name;

trait Ext: Sized {
    fn test(self: &Self) {
        println!("{}", type_name::<Self>())
    }
}

impl<T> Ext for &T {}

fn main() {
    (&String::new()).test(); // output:&alloc::string::String
}

如果把函数参数改为 self: Self 结果也一样:Self 类型是 &String

第二段代码:

use std::any::type_name;

trait Ext: Sized {
    fn test(self: &Self) {
        println!("{}", type_name::<Self>())
    }
}

impl<T> Ext for T {}

fn main() {
    (&String::new()).test(); // output:alloc::string::String
}

与上段代码的区别是:这次是 impl for T,然后 Self 类型变成了 String; 如果把函数参数改为 self: Self 结果会变成 &String

看起来,第二段代码在Self的类型声明处发生了模式匹配:将传入的 &Self&String 做匹配,得出 SelfString(有人也称其为“自动解引用”)

我的问题是:为什么第一段代码没有发生 模式匹配/自动解引用?因为纯泛型T是特例吗?

评论区

写评论
ywxt 2021-03-20 19:54

因为T可以匹配T&T,&mut T, 而&T只可以匹配&T

参考 常见的Rust lifetime误解

c5soft 2021-03-20 08:54

把亲的代码整理一下:

use std::any::type_name;

trait Ext {
    fn ext_with_at_self(&self) {
        println!(
            "Ext for T call with &self, type_name of Self is {}",
            type_name::<Self>()
        )
    }
    fn ext_with_self(self)
    where
        Self: Sized,
    {
        println!(
            "Ext for T call with  self, type_name of Self is {}",
            type_name::<Self>()
        )
    }
}

impl<T> Ext for T {}

trait ExtAt {
    fn ext_at_with_at_self(&self) {
        println!(
            "Ext for &T call with &self, type_name of Self is {}",
            type_name::<Self>()
        )
    }
    fn ext_at_with_self(self)
    where
        Self: Sized,
    {
        println!(
            "Ext for &T call with  self, type_name of Self is {}",
            type_name::<Self>()
        )
    }
}

impl<T> ExtAt for &T {}

fn main() {
    let a = String::new();
    println!("self is String");
    a.ext_with_at_self();
    a.ext_with_self();
    let a = &String::new();
    println!("self is &String");
    a.ext_with_at_self();
    a.ext_with_self();
    
    println!();

    let a = String::new();
    println!("self is String");
    //a.ext_at_with_at_self(); //this line refused by compiler
    println!("Ext for &T call with &self, can not be compiled");
    a.ext_at_with_self();
    let a = &String::new();
    println!("self is &String");
    a.ext_at_with_at_self();
    a.ext_at_with_self();
}

运行结果:

self is String
Ext for T call with &self, type_name of Self is alloc::string::String
Ext for T call with  self, type_name of Self is alloc::string::String
self is &String
Ext for T call with &self, type_name of Self is alloc::string::String
Ext for T call with  self, type_name of Self is &alloc::string::String

self is String
Ext for &T call with &self, can not be compiled
Ext for &T call with  self, type_name of Self is &alloc::string::String
self is &String
Ext for &T call with &self, type_name of Self is &alloc::string::String
Ext for &T call with  self, type_name of Self is &alloc::string::String
1 共 2 条评论, 1 页