为什么 f# 会在没有警告或错误的情况下改变不可变变量?

Why does f# mutate an immutable variable without warning or error?

以下脚本在没有错误或警告的情况下改变不可变变量 jar。 这是一个错误吗?还是我的理解有问题?

请解释为什么我不需要使用 mutable 关键字。

旁白:FSharp.Data.Http.RequestString 的 cookieContainer 参数在定义中未标记为可变:https://github.com/fsprojects/FSharp.Data/blob/134a08cda3acb8e746bb25d03692d90ee5caabab/src/Net/Http.fs

#r "System.Xml.Linq.dll";;
#r "nuget:FSharp.Data";; 

open FSharp.Data

let url="http://www.google.com"
let uri=System.Uri(url)

// no mutable keyword here
let jar=System.Net.CookieContainer()

// Count is 0
printf $"Pre-request cookie count is: {jar.GetCookies(uri).Count}\n"

let r = Http.RequestString(url, cookieContainer=jar) 

// Count is 1
printf $"Post-request cookie count is: {jar.GetCookies(uri).Count}\n" 

#r "System.Xml.Linq.dll";; #r "nuget:FSharp.Data";;

在 F# 中有两个与变异相关的不同概念:

  • 可变变量,即可以改变值的变量。它们是使用 let mutable 定义的,您可以使用 <- 更改值(如果变量不可变,这是不可能的)。

  • 可变对象 只是具有一些可变状态的 .NET 对象,可以通过调用对象上的方法来更改这些状态​​。这些是普通 C# 风格的实例 类.

如果您定义一个不可变变量,它是对可变对象的引用,该对象仍然可以被改变。变量不可变的事实并不能阻止这种情况的发生。这就是你的情况。

就像有不可变的变量一样,也有不可变的对象(或值)。这包括 F# 数据类型,如记录和可区分联合。然而,对象是否可变这一事实并没有在语言中被追踪——所以这是你无法以任何明显的方式看到的东西。

在 well-designed F# 代码中,您自己的大部分对象都是不可变的,但您使用的大多数 .NET 对象(用于访问 .NET 提供的功能)都是可变的 - 因为这就是方式.NET 的设计。