移动语义对 Rust 中的引用透明性意味着什么?

7

我正在尝试弄清楚移动语义是如何影响引用透明性的。

引用透明性(RT)允许我们将任何表达式替换为其结果,而不改变程序的含义(摘自Scala函数式编程)。例如,我可以在程序中的任何位置将1+1替换为2,而什么都不应该改变。这个Python程序具有引用透明性:

@dataclass
class Bucket:
    things: List[str]

leaves = ["leaves"]

def bucket_with_sand(things: List[str]) -> Bucket:
    return Bucket(things + ["sand"])

bucket_with_sand(leaves)  # can be replaced with Bucket(["leaves", "sand"]) with no change to the program

而这个函数会直接在原参数上进行修改。

def bucket_with_sand(things: List[str]) -> Bucket:
    things += ["sand"]
    return Bucket(things)

所以将函数调用替换为其结果将改变其含义。它不再具有引用透明性。在像Rust的移动语义这样的语言中,我们可以通过移动leaves(并依赖于Vec不是Copy)来避免此问题:

struct Bucket {
    things: Vec<&str>,
}

let leaves = vec!["leaves"];

fn bucket_with_sand(things: Vec<&str>) -> Bucket {
    things.push("sand");
    Bucket { things }
}

bucket_with_sand(leaves); // mutates `things`
// doesn't matter that `leaves` has been mutated here as it's now out of scope

这似乎再次表现为引用透明。这是正确的吗?这样的移动是否放松了关于RT设计的传统限制?还是这些移动不是引用透明的?我特别想知道是否有更广泛的RT影响我没有看到。

好的,你的函数内部改变了某些东西,但如果你只谈论函数可能产生的副作用,那么是的,给它所有权并确保没有外部副作用。 (但不要忘记 Rust != Haskell,不要仅仅因为这个就给一个向量所有权,这不是 Rust 的方式) - Stargateur
@Stargateur,你能详细说明一下“这不是 Rust 的方式”的原因吗?为什么不是这样做呢? - joel
特别是,它似乎是一种非常聪明的FP方法,而不必“处理”副作用。 - joel
我觉得这似乎与纯函数的概念有关。 - Boiethios
1个回答

6
"引用透明性"的概念在几乎所有在真实计算机上执行的语言中都有些模糊,尤其是在具有命令式状态的语言中,Rust也不例外。一个调用可能会产生副作用——从执行IO到耗尽内存到仅仅改变可变变量的任何事情——并且根据您是否将这些包含在您的“没有变化”的意义中,您可能会认为函数是非引用透明的。它们不是纯数学函数,而是在调用时改变世界状态的过程。"

话虽如此:Rust的所谓“所有权”系统——将“一次性使用”或“移动”类型与其多读单写借用系统相结合——有助于大大减少程序中可能出现的副作用。特别是(大部分情况下*),它消除了大多数其他命令式语言中最普遍和有害的副作用:可变别名。也就是说,在Rust中,您(大部分情况下*)永远不会有两个或更多对同一内存位置的引用,其中一个函数中的一个引用在运行时作为副作用改变内存位置,而另一个函数中的另一个引用只是看到内存位置中的值“突然改变”。这意味着任何时候要修改值,都将通过其唯一当前引用——即&mut或拥有变量——进行修改,这意味着,正如您在这里提问的那样,在Rust中关于参考透明度的假设有比大多数其他命令式语言更高的成真率。

上面的星号"(大多数*)"表示一个相当大的例外:不安全的代码可以违反这个规则,并且在几个库函数中确实这样做。例如,Rust标准库提供了所谓的"内部可变性"的部分,提供了不安全的cell类型和强制执行可变别名禁止规则的包装类型动态地,以时间为基础:这样的可变访问可以在给定的时间发生,但它们被允许从不同的共享引用顺序地进行。

几乎每一种真实语言都有同样的警告,无论它自己如何“纯粹”:ML系列有ref单元格,Haskell有其不安全的库函数,Lisp有set!等等。这些都是为了让程序能够通过数学抽象(在函数式语言中是纯值,在Rust的情况下是仿射值)达到底层机器的无限制可变别名,从而获得压倒性的性能优势。

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