rust `时雄::pin`如何改变变量的类型?

bqf10yzr  于 2023-06-23  发布在  其他
关注(0)|答案(1)|浏览(114)
use std::pin::Pin;

fn print_type_of<T>(_: &T) {
    println!("{}", std::any::type_name::<T>())
}

fn test(s: String) {}
fn test2(s: Pin<&mut String>) {}

fn main() {
    let s = String::from("abc");
    print_type_of(&s);
    tokio::pin!(s);
    print_type_of(&s);
    // test(s); error!
    test2(s);
}

问题不在于为什么Pin是什么或者为什么需要Pin
调用tokio::pin!后,s的类型从alloc::string::String变为core::pin::Pin<&mut alloc::string::String>。怎么会这样?在宏中改变外部变量的类型让我感到惊讶。

ar7v8xwq

ar7v8xwq1#

宏比函数更强大。它们在编译时被评估,并转换为代码 * 在同一范围内 * 它们被调用。尽管如此,宏can't access variables in that scope with hardcoded names, but it can if the identifier is received as a parameter.
还请注意,Rust允许隐藏(重新声明)同名变量。
例如:

let x = 42;

print_type_of(x); //i32

let x = "foo";

print_type_of(x); //&str

工作正常。这两个x 'es实际上并不是同一个变量,它们只是具有相同的标识符(“name”),而后者使前者不可访问。
而宏 * 可以 * 发出隐藏变量的行。所以:

macro_rules! print_and_replace {
    ($var: ident) => {
        println!("{}", $var);
        let $var = "foo";
    };
}

fn main(){
    let x = 42;

    print_and_replace!(x);

    println!("{x}");
}

就像你写的一样

fn main(){
    let x = 42;

    println!("{}", x);
    let x = "foo";

    println!("{x}");
}

至于为什么tokio::pin需要这样做,堆栈固定要求原始值永远不会再次移动。它可以通过隐藏变量来确保这一点,使其不再可访问。
所以pin并不比这个多:

macro_rules! pin {
    ($var: ident) => {
        let $var = unsafe{ Pin::new_unchecked(&mut $var) };
    }
}

相关问题