gpt4 book ai didi

rust - 内联一个常用方法

转载 作者:行者123 更新时间:2023-11-29 08:13:54 24 4
gpt4 key购买 nike

我想在不知道谁实现了 TraitA 的情况下内联 TraitA::x() 方法。

例如:

(注意:StructB 实现了 TraitA。)

let a: &TraitA = &StructB { x: 0f32 };
a.x(); // This should access `a.x` field directly
// as `TraitA::x()` always return the same field,
// the same `b.x` field slot.

该方法将在不同的结构中以相同的方式实现。

trait TraitA {
fn x(&self) -> f32;
}

struct StructB {
x: f32
}

impl TraitA for StructB {
#[inline]
fn x(&self) -> f32 {
self.x
}
}

a.x() 会内联到 (a as &StructB).x 吗?

我可以在 C++ 上做得很好,例如:

class A {
float _x;

public:
float x() {
return _x;
}
};

struct B : A {};

int main() {
A* a = new B;
a->x();
}

最佳答案

我认为您在这里混淆了一些事情。首先:在纯虚拟上下文中使用特征时,不可能从特征中内联方法(也就是说:您没有关于实际类型的信息)。这看起来像这样:

fn unknown_type(foo: &MyTrait) -> f32 {
foo.x()
}

在这里,编译器不可能知道 trait 对象 foo 背后的实际类型。因此,它被迫使用 vtable 并进行动态调度来调用该方法。有一种称为去虚拟化 的优化,它会尝试猜测正确的类型来执行静态分派(dispatch)(甚至内联方法),但这种优化有其局限性。

Will a.x() get inlined to (a as &StructB).x?

在大多数情况下是的,但这与您的内联属性或特征对象无关。在您的小示例中,编译器可以看到整个函数并且知道 a 具有基础类型 StructB。但同样,这不是一个纯粹的虚拟上下文:编译器有它可以使用的类型信息。


另一件事:这一切都与 Java 中的 final/C# 中的 f 无关——如 the first version of your question 中所述.

这些关键字仅对类层次结构有用。由于原则上您可以在派生类中重写 Java/C# 中每个类的所有方法,因此理论上编译器永远不会内联或静态分派(dispatch)方法。它总是必须检查 vtable 以检查是否有此方法的更专业版本。当编译器有一个将该方法声明为 final 的类的变量时,它可以静态调用它,因为它保证它不会被覆盖。

但在 Rust 中拥有一个特征对象(关于这个问题)等同于拥有一个具有接口(interface)类型的变量。而且您(显然)不能将接口(interface)方法声明为 final。因此,在这里,无论某些实现类是否将其实现声明为 final,编译器都必须执行虚拟分派(dispatch)。


此外,您的 C++ 与您的要求没有任何关系。基类 A 声明了一个带有方法体的非虚函数。这意味着该函数永远不会在虚拟上下文中调用。但是在你的 Rust 代码中 x() 没有主体并且可以在虚拟上下文中使用。

在 Rust 中没有类似的东西,但你可以通过 impl Trait { ... } 向特征对象添加方法。该特征的实现者无法重写这些方法,因此编译器可以轻松执行静态分派(dispatch)或内联方法。

您可以看到该示例及其程序集 here .


回答我认为你实际要问的问题:

You want to inline that trait method call so that it's as cheap/fast as a simple field access of a concrete type, right?

这在纯虚拟环境中也是不可能的。当编译器不知道实现类型时,它无法生成简单的字段访问,因为它不知道该字段相对于基指针的偏移量!我的意思是,并非所有实现类型都保证具有相同的内存布局并始终将 x 保持在相同的位置。

但是,可以比方法做得更好:不调用 getter 方法,而是可以将字段偏移量存储在 vtable 中并使用它来索引字段。这仍然比标准字段访问更昂贵,但比方法调用更快。

这正是 this RFC: "Allow fields in traits that map to lvalues in impl'ing type" 中提出的建议. RFC 线程已关闭,但 RFC 仍在开发中。

所以你现在不能那样做。使用特征方法是您现在可以做的最好的事情。

关于rust - 内联一个常用方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51698722/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com