< 返回版块

acodercat 发表于 2020-05-12 16:00

Tags:型变

已知fn(T)在T上是逆变的,也就是fn(&'a str)类型可以转换为fn(&'static str)。那么反过来fn(&'static str)不能转换为fn(&'a str)。下面代码会报错是正常的:

  fn f1<'a>(f:  fn(&'static str)) {
        let a: fn(&'a str) = f;
    }

但是不知道为什么下面这段代码不会报错:

fn f2<'a>(f: fn(&'a str)) {
 }
fn f1(f:  &'static str) {
}
f2(f1);

都是转换,一个是直接赋值,另外一个是实参到形参。为什么会不一样呢?

评论区

写评论
importcjj 2020-05-12 21:55

在第一个例子里,生命周期'a可以是'static的,也可以是其他长度,所以'static'a的 subtyping,而fn(T)->()是逆变的(唯一的逆变),根据逆变的规则,fn(&'a i32)类型可以赋值给fn(&'static i32),反之不行。所以第一个例子失败,但是以下例子是成功的

 fn f1<'a>(f:  fn(&'a str)) {
    let a: fn(&'static str) = f;
}

而第二个例子,就没那么难搞了,当函数f2作为参数传入f1时, f1里的'a就被指定为'static了,其实就变成了

fn f2<'static>(f: fn(&'static str)) {
}

自然没有问题了

xjkdev 2020-05-12 16:18

你理解错了,在rust里除了'static这样特殊的生命周期,'a,'b这样的一般都只是一个”变量“,表示某一个生命周期。

'a和'static没有一定的“继承”或者包含的关系。在你的例子中,'a都是一种模板中的生命周期”变量“。(这里使用双引号表示这个说法可能不太标准,下同)

在第一段代码中,因为'a在模板中,在传入时才确定,而不是所有生命周期都能”转化为“'static,所以编译器拒绝了。

但第二段代码中,由于你传入的是一个'static的周期,因此模板自动推算出'a就是'static,因此能成功。

vkill 2020-05-12 16:17

下面的能通过是对的嘛

这种情况下 f2<'a> 这个地方的 'a 等于 'static

1 共 3 条评论, 1 页