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>.这怎么会发生呢?更改宏内的外部变量的类型让我感到惊讶.

推荐答案

宏比函数更强大.它们在编译时求值,并转换为代码in the scope,在其中被调用.尽管如此,宏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实际上并不是同一个变量,它们只是有相同的名称(后者使前者不可访问).

并且宏can发出隐藏该变量的行.所以:

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}");
}

*:如果标识符是通过参数传入的.如果宏tried to access x directly.


至于为什么tokio::pin需要这样做,堆栈锁定要求不再移动原始值.它可以通过跟踪变量来确保这一点,使其不再可访问.

所以pin并不比这个多多少:

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

Rust相关问答推荐

如何在 struct 中填充缓冲区并同时显示它?

为什么类型需要在这个代码中手动指定,在rust?

我怎样才能从一个Rust 的日期中go 掉3年?

如何从铁 rust 中呼唤_mm_256_mul_ph?

文档示例需要导入相关的 struct ,但仅在运行测试时.这是故意的行为吗?

如果LET;使用布尔表达式链接(&Q);

如何获取Serde struct 的默认实例

如何计算迭代器适配器链中过滤的元素的数量

如何使用RefCell::JOYMOMTborrow 对 struct 不同字段的可变引用

不能在Rust中使用OpenGL绘制三角形

失真图像图形捕获Api

`use` 和 `crate` 关键字在 Rust 项目中效果不佳

更新 rust ndarray 中矩阵的一行

为什么需要同时为值和引用实现`From`?方法不应该自动解引用或borrow 吗?(2023-06-16)

错误:将自定义 proc_macro 与用Rust 的宝贝编写的属性一起使用时,无法在此范围内找到属性

将 `&T` 转换为新类型 `&N`

在 Rust 中获得准确时间的正确方法?

A 有一个函数,它在 Option<> 类型中时无法编译,但在 Option<> 类型之外会自行编译.为什么?

如何重写这个通用参数?

令人困惑的错误消息? (解包运算符)