8.2.3.1 可变状态使用引用单元

要回答这个问题,我们需要能够创建一些要捕获的状态。一个方法是用 let mutable,但是,这样,并不能运行,因为这种可变值只能用于局部,不能被闭包捕获。

第二个方法是使用引用(ref)类型创建可变值,即引用单元(reference cell)的缩写,它是能够包含可变值的小对象(实际上,声明为 F# 的记录类型)。要理解引用类型的原理,我们在 C# 中定义同样的类型,可以看到,相当简单:

class Ref<T> {

public Ref(T value) { Value = value;}

public T Value { get; set; }

}

这里最重要的是 Value 属性是可变的,所以,当我们创建了一个不可变的 Ref<int>类型的变量时,仍然可以改变它代表的值。清单 8.8 是在 F# 中使用引用单元的例子,显示了相当于 C# 使用Ref<T> 类型的代码;在 F# 中,不直接访问类型,因为有一个函数,也叫 ref,创建引用单元,以及设置和读取值的两个运算符。

清单 8.8 在 F# 和 C# 中使用引用单元


F# Interactive


C#


let st = ref 10

st := 11

printfn "%d" (!st)


var st = new Ref<int>(10);

st.Value = 11;

Console.WriteLine(st.Value);

第一行,我们创建了一个包含整数的引用单元,如同刚刚在 C# 中声明的 Ref<T>  类型一样,F# 的 ref 类型是泛型的,所以,我们可以用它来保存任何类型的值;接下来的两行演示了使用引用单元的运算符:赋值(:=)和取消引用(!),F# 的运算符对应于设置和读取属性值,但语法更便利。

[

在 F# 4.0 中,对可变值的使用进行了简化。

在 F# 中,虽然值默认是不可变的,但是,可变值也是是允许的。过去,关键字 mutable用于说明可变值使用栈,这种值使用 <- 运算符进行修改;如果可变值是由闭包捕获的,那么值就使用堆,需要使用ref 语法,愈发值是通过 := 运算符。

这些语法上的差异既使代码不优雅,也让开发人员困惑,很难弄清楚到底应该使用哪一种方法。

现在,使用 F# 4.0,开发人员只要用一个关键字 mutable,就能搞定所有可变值,余下的工作由编译器完成:如果可能,就在栈上创建变,否则,隐式转换成引用单元。

对于非常了解栈、堆语有钱人高级用户,能够启用警告 3180(在 fsc.exe 或 fsi.exe 中,使用 --warnon:3180),当 mutable 声明隐式转换成 ref 时,会发出通知。

]

时间: 2024-10-29 02:11:46

8.2.3.1 可变状态使用引用单元的相关文章

8.2.3.2 在闭包中捕捉引用单元

现在,我们可以编写代码,捕获在闭包中使用引用单元创建的可变状态.清单 8.9 显示了可配置收入检查的 F# 版本.我们创建了 createIncomeTests 函数,返回有两个函数的元组:第一个函数改变所需的最低收入,第二个函数测试函数自身. 清单 8.9 使用闭包测试可配置收入 (F# Interactive) > let createIncomeTest () = let minimalIncome= ref 30000   [1] (fun (newMinimal)–> minimal

Excel中公式的绝对引用和相对引用单元格

在Excel的表格中,非常常用的就是公式里的绝对引用和相对引用了,具体情况请看下列表格吧 步骤1 打开做好的excel表格.公式中的相对单元格引用是基于包含公式和单元格引用的单元格的相对位置,若公式所在的单元格位置改变,则引用也随之改变. 1.选定单元格I3,其中的公式为“=SUM(C3:H3)”,求得个人的总分 2.制定单元格I3右下角的填充柄,鼠标指着变成十形时,按住鼠标左键不放向下拖拽到要复制公式的区域 3.释放鼠标后,即可完成复制公式的操作. 步骤2 亲们注意到了没,在I3的公式为“=S

有用函数编程

<序> 感谢 关于本书 关于封面 第一部分 学习函数式思维 第一章 不同的思维 1.1 什么是函数式编程? 1.2 通往有用函数编程之路 1.3 用函数式编程提高生产力 1.3.1 函数范式 1.3.2 声明式编程风格 1.3.3 了解程序的执行 1.3.4 设计并发友好的应用程序 1.3.5 函数风格怎样形成代码 1.4 函数式编程演示样例 1.4.1 用声明式风格表达意图 1.4.1.1 用 LINQ 处理数据 1.4.1.2 用 XAML 描写叙述用户界面 1.4.1.3 声明式函数动画

《java并发编程实战》读书笔记3--对象的组合

希望将一些现有的线程安全组件组合为更大规模的组件或程序 设计线程安全的类 如果对象中所有的域是基本类型变量,那么这些域将构成对象的全部状态.例如,LinkedList的状态就包括该链表中所有节点对象的状态.要确保线程的安全性,就需要确保它的不变性条件不会在并发访问的情况下被破坏. 实例封闭 当一个对象被封装到另一个对象中时,能够访问被封装对象的所有代码路径都是已知的.通过将封闭机制与合适的加锁策略结合起来,可以确保以线程安全的方式来使用非线程安全的对象.被封闭对象一定不能超出它们既定的作用域.来

Java Concurrency

1.简介 2.线程安全性 2.1什么是线程安全性 3.对象的共享 4.对象的组合 4.1设计线程安全的类 4.2实例封闭 本文参考<Java Concurrency in Practice>. 1.简介 编写正确的进程很难,而编写正确的并发进程则难上加难. 2.线程安全性 要编写线程安全的代码,核心在于要对状态访问操作进行管理,特别是对共享(Shared)和可变(Mutable)状态的访问.从非正式意义上来说,对象的状态是指存储在状态变量(例如实例或静态域)中的数据.对象的状态可能包括其他依赖

函数对象状态(Function Object State)获取 -- 引用传递和for_each()

一般情况下function object默认值传递,无法获取其状态.本文以引用传递和for_each()两种方法获取function object状态. 引用方式传递function object 以引用方式传递function object程序示例: #include <iostream> #include <list> #include <algorithm> #include <iterator> using namespace std; templa

java-并发-不可变对象

当一个对象创建后的状态不可改变时就认为其为不可变对象,尽可能地利用不可变对象被公认为是构建简单可靠代码的有效方法.不可变对象在并发程序中比较有用,由于其状态无法改变,因此无法被线程的干扰损坏或者被视为不一致状态. 程序员一般不愿意使用不可变对象,因为他们担心创建一个新对象可能会比更新一个已有对象的状态代价更大,然而往往创建一个对象的影响会被高估,而且会被与不可变对象相关的高效性补偿,这包括降低垃圾回收的开支,免除需要防止可变对象被损坏的代码. 不可变对象语法上没有新的内容,以下定义了一些创建不可

手把手教你用ngrx管理Angular状态

本文将与你一起探讨如何用不可变数据储存的方式进行Angular应用的状态管理 :ngrx/store--Angular的响应式Redux.本文将会完成一个小型简单的Angular应用,最终代码可以在这里下载. Angular应用中的状态管理 近几年,大型复杂Angular/AngularJS项目的状态管理一直是个让人头疼的问题.在AngularJS(1.x版本)中,状态管理通常由服务,事件,$rootScope混合处理.在Angular中(2+版本),组件通信让状态管理变得清晰一些,但还是有点复

多线程编程-设计模式之不可变对象模式

Immutable Object设计模式适用场景:1.被建模对象的状态变化不频繁:设置一个专门的线程用于被建模对象状态发生变化时创建新的不可变对象.而其他线程只是读取不可变对象的状态.此场景下一个小技巧就是Manipulator对不可变对象的引用使用volatile关键字进行修饰,既可以避免使用显示锁比如synchronize,又可以保证多线程间的内存可见性.2.同时对一组相关的数据进行写操作,因此需要保证原子性此场景下为了保证操作的原子性,通常的做法是使用显示锁,但若采用Immutable O