你能在Rust中指定返回类型的可变性吗?

3
在Rust中,是否可以指定分配的变量的可变性?例如:
fn new(len: usize) -> Thing { ... }
fn new_mut(len: usize) -> mut Thing { ... }

我有一个特定的案例,需要知道一个类型的可变性,以便在我的数据结构下进行多种优化。

手动强制可变性是可能的,但似乎相当不雅,特别是当可变性的概念已经是 Rust 语言固有的一部分时。你最终会陷入奇怪的境地,就像这样:

// Thing::new() returns a data structure with an immutable backing type, 
// but the code below looks like it should be mutable.
let mut foo = Thing::new(5);

在这种情况下,我要么尝试找出是否有人手动尝试将可变引用指向我的不可变Thing(并且可能会产生恐慌),要么通过使new返回一个包装器覆盖了所有可变函数的Thing来隐藏所有可变函数(这意味着mut关键字变得毫无意义和误导性)。

据我所知,不行。因为在方法返回后,值的所有权会改变到调用该方法的上层作用域,所以方法本身无法在那一点上控制可变性。 - sertsedat
8
若可变和不可变的“Thing”表现有如此大的差异,为何不将它们创建为不同类型?一个是“Thing”,另一个是“ThingMut”。 - kmdreko
1
我已经修改了这段代码,其中Thing::new返回一个不可变的_引用_。我不确定是否可能在不是引用类型的情况下编码可变性或不可变性。在我看来,像let mut foo = Thing::new(5);中所见的可变性是变量的属性,而不是其类型的属性。因此,据我所知,写let a: mut u32 = 42;是不可能的,因为会出现"expected type, found keyword mut"的错误,但可变的_引用_是可以的。 - ForceBru
4
let mut foo = Thing::new(5); 中,我认为可变性是变量的属性,而不是其类型。这是正确的。此外,由于遮蔽的存在,可以在不改变变量的名称的情况下改变其可变性:let mut foo = Thing::new(5); do_something(&mut foo); let foo = foo; 是有效的。 - Cerberus
1
@Cerberus 同样,反过来也是有效的,这真的会让一些人感到困惑:let foo = Thing::new(5); /* 这里 foo 是不可变的 */ ... let mut foo = foo; /* foo 不再是不可变的! */ ... - user4815162342
1个回答

10
我认为您有一些误解:返回类型的可变性不应该是函数签名的一部分,也不能成为其一部分。可变性总是由调用方决定。
返回类型是描述在执行函数后,从调用栈返回给调用者的内存插槽。返回类型的所有权已经完全转移,例如,一个 Thing 已经完全移交给了调用者。如何处理返回的内存单元不是调用函数所关心的问题,因为它已经完成并返回。没有可变或不可变的返回类型,可变性总是与内存插槽有关。在您的示例中,只有在声明变量 foo 定义了结果类型的内存插槽时才会决定此项。只要您拥有数据结构的全部所有权,就可以自由地决定甚至更改数据的可变性。
您正在寻找的可能是专门用于优化的单独类型。

对于第一个短语不确定。Vec::get_mutHashMap::entry返回对后台变量的可变引用,而Vec::get则返回非可变引用。因此,使用类似Option OP的包装器可能可以实现相同的行为。 - SirDorius
我理解你的观点,也许我的措辞并不完全清楚。我的意思是返回值的可变性,也就是在你的情况下引用本身是由调用者控制的。无论引用是只读的还是可以重新分配指向其他地方,都与函数签名无关,需要在调用者这一方面决定。被引用数据的可变性是一个完全独立的话题,你说得对,它确实是签名的一部分。 - Zólyomi István

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