为什么我需要用()包裹一个闭包?

4
struct Counter<T>
where
    T: Fn() -> i32,
{
    generator: T,
    val: i32,
}

impl<T> Counter<T>
where
    T: Fn() -> i32,
{
    pub fn new(gen: T) -> Counter<T> {
        Counter {
            generator: gen,
            val: 0,
        }
    }
    pub fn next(&mut self) {
        self.val = (self.generator)(); // This works
        // self.val = self.generator(); // This does not work
    }
    pub fn get(&self) -> i32 {
        self.val
    }
}

上面是一个小例子,我在结构体中使用了一个闭包。当我通过generator()调用闭包时,会出现no method named generator found的错误。但当我用()包装它时,就不会出现这个问题。为什么会这样呢?

1
为什么?因为这是语言的规则。您需要用括号将存储在字段中的函数调用起来。 - Chayim Friedman
2
ref:字段表达式后面不能跟随一个括号逗号分隔的表达式列表,因为这将被解析为方法调用表达式。也就是说,它们不能是调用表达式的函数操作数。 - Ömer Erden
2
由于 self 是一个关键字,另一种看待它的方式是 self.generator()Self::generator(self) 的语法糖,这显然需要存在一个 generator 方法。括号只是强制表达式被解释为更一般的 foo(bar) 函数调用语法,而不是方法解糖,这就是为什么在你的情况下它们做正确的事情。你可以通过以下方式实现相同的结果,而不需要括号:let generator = &self.generator; self.val = generator(); - user4815162342
1个回答

9

Rust中的类型可以同时具有与字段和方法相同名称的属性,例如:

struct Foo {
    bar: i32,
}

impl Foo {
    fn bar(&self) -> i32 {
        self.bar
    }
}

fn main() {
    let foo = Foo { bar: 42 };
    dbg!(foo.bar());
}

命名getter方法与它们获取的字段相同是一种常见惯例(按照Rust惯例)。Rust语言设计师决定通过使用不同的语法来访问它们,避免字段名称和方法名称之间的冲突。形如foo.bar()的表达式始终调用一个方法。而形如foo.bar的表达式直接引用一个字段。因此,如果您想调用存储在字段中的函数指针,则需要在字段访问表达式周围添加额外的括号。


非常感谢。这让事情更加清晰了。 - User12547645

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接