我听说 F# 本身支持不可变性,但是 C# 不能复制它的部分特性。使用 F# 不可变数据类型,你获得了什么,而 C# 不可变数据类型没有的呢?
另外,在 F# 中是否没有创建可变数据的方法?一切都是不可变的吗?
如果在一个应用程序中同时使用 C# 和 F#,能否在 C# 中更改不可变的 F# 数据?或者你只需要创建新的 C# 类型,使用不可变的 F# 数据并替换指向这些数据的引用。
我听说 F# 本身支持不可变性,但是 C# 不能复制它的部分特性。使用 F# 不可变数据类型,你获得了什么,而 C# 不可变数据类型没有的呢?
另外,在 F# 中是否没有创建可变数据的方法?一切都是不可变的吗?
如果在一个应用程序中同时使用 C# 和 F#,能否在 C# 中更改不可变的 F# 数据?或者你只需要创建新的 C# 类型,使用不可变的 F# 数据并替换指向这些数据的引用。
F#的工作方式使得使用不可变数据更加容易,但在C#中也可以做到这一点,只是可能没有那么简洁的语法。
F#使用mutable
关键字支持可变数据。F#不是纯函数式语言,它还支持像循环等命令式构造。
不可以。不可变类型是真正的不可变的,.NET类型系统适用于两种语言。当然除了反射和内存hack之外,你也无法从C#中修改不可变数据。
Mehrdad已经回答了你的所有问题,但是只是为了进一步解释#1- 差异在于您需要编写的代码量。例如,这是C#中只读点的定义和示例用法:
class Point
{
private readonly int x, y;
public int X { get { return x; } }
public int Y { get { return y; } }
public Point(int x, int y)
{
this.x = x;
this.y = y;
}
}
var p = new Point(1, 2);
你可以使用自动属性来缩短代码,但这样只能确保客户端的不可变性,无法确保类定义内部的不可变性。type Point = { x: int; y: int }
let p = { x = 1; y = 2 }
如果你希望它是可变的:
type Point = { mutable x: int; mutable y: int }
let p = { x = 1; y = 2 }
p.x <- 3
p.y <- 4
<-
与赋值操作符 =
是不同的。这可以防止你在无意中改变状态,因为你必须明确地表达它。同时,这种语法具有不太方便的语法结构,可以避免在没有绝对必要的情况下使用可变值。 - Joel Muelleryield return
),如果在C#中可能存在的话。请参阅http://msdn.microsoft.com/en-us/library/dd233209(VS.100).aspx。如果您指的是LINQ to SQL-即在运行时分析语法树及其转换为其他内容,则F# PowerPack支持此功能。 - Pavel MinaevF# 相对于 C# 最大的不同在于默认情况下 F# 是不可变的。虽然在 C# 中可以复制所有不可变结构和集合,但需要付出很多额外的努力。而在 F# 中,你只需要轻松获得。
F# 是混合语言并支持一些形式的可变性。最简单的是 mutable 关键字。
let value1 = 42; // immutable
let mutable value2 = value1; // mutable
value2 <- 13;
除了反射技巧,一旦数据在F#中创建,无论您从哪种语言使用它,它都是不可变的。
type MyRect = { X : int; Y : int; Width : int; Height : int }
let r = { X = 0; Y = 0; Width = 200; Height = 100 }
// You'll often need to create clone with one field changed:
let rMoved1 = { X = 123; Y = r.Y; Width = r.Width; Height = r.Height }
// The same thing can be written using 'with' keyword:
let rMoved2 = { r with X = 123 }
你也可以用C#编写相同的内容,但是需要声明不可变的数据结构,并使用方法WithX
返回一个带有修改后的X
字段的克隆对象,以及WithY
、WithWidth
等方法。以下是不完整示例:
class MyRect {
readonly int x, y, width, height;
MyRect WithX(int newX) {
return new MyRect(newX, y, width, height);
}
// etc...
}
没有编译器的帮助,这是很多工作。
使用F#不可变数据相较于C#不可变数据,你能获得什么?
F#允许你轻松地创建不可变数据的修改副本,在C#中这非常繁琐且耗时。考虑在F#中创建一个记录:
type Person = { FirstName: string; MiddleName: string; LastName: string }
let me = { FirstName = "Robert"; MiddleName = "Frederick"; LastName = "Pickering" }
假设我想修改F#中的姓氏字段,可以使用“with”关键字进行复制:
let me' = { me with LastName = "Townson" }
let myList = [3; 2; 1]
let myList' = 4 :: myList
let newarr = mangle(oldarr)
。虽然每次都制作一个新副本的成本很高,但可以设计数据结构以利用不可变性通过共享结构;例如,如果你有链表 A = (3, 2, 1) 和链表 B = (4, 3, 2, 1),并且两者都是不可变的,那么链表 B 可以由 4 和指向 A 头部的指针表示。树也可以做同样的事情。 - mqp