7.1.2 C# 中的函数式数据结构

我们曾经用 C# 实现过几个函数式不可变数据类型,比如 FuncList 或元组。在 C# 中,是通过以特殊方式写类来实现的,最重要的是,所有属性必须是不可变的,这是通过使用只读字段,或者通过声明的属性具有私有的 setter,且只在类的构造函数中设置来实现。在清单 7.3 中,我们使用第一种方法实现似于类清单 7.1 中 Rect 类型的类。

清单 7.3 不可变 Rect 类型 (C#)

public sealed class Rect {

private readonly float left, top,width, height;

public float Left { get { returnleft; } }      |  返回只读属性的值

public float Top { get { return top;} }      |

public float Width { get { returnwidth; } }  |

public float Height { get { returnheight; } } |

public Rect(float left, float top,float width, float height) {  <-- 构造矩形

this.left = left;this.top = top;

this.width = width;this.height = height;

}

public Rect WithLeft(float left){   [1]

return new Rect(left,this.Top, this.Width, this.Height);  <-- 创建对象的副本

}

// TODO: WithTop, WithWidth andWithHeight

}

这个类包含的字段,在构造函数中初始化时,使用了只读修饰符进行标记。这是用 C# 实现真正不可变类或值的正确方法;在 C# 3.0中,也可以使用自动属性与私有的 setter,代码更简短,那样的话,我们的责任是确保仅在构造函数中设置属性。

WithLeft 方法[1]中更有意义的部分是,它能够用修改后的 Left 属性值创建对象的副本。我们省略掉其他属性,因为,类似的方法很容易实现;这些方法对应于我们前面看过的 F# 记录的 with 关键字。可以看到相似性:

let moved = { rc with Left = 10.0f }

var moved = rc.WithLeft(10.0f);

最重要的一点是,我们不必显式读取 Rect 类的所有属性,只要列出更改过的属性。这种语法非常优雅,即使我们想要修改属性不止一个:

var moved =rc.WithLeft(10.0f).WithTop(10.0f);

正如我们在此示例中所看到的,我们经常需要同时设置两个相关的属性。如果经常发生这种情况,更方便的方法是,添加新的方法以创建一个副本,并修改所有相关的属性。在我们的示例中,我们也可以添加方法WithPosition 和 WithSize,因为,它们表示的操作很常用;如果每次单独改变创建的对象不是正确的状态,而只有组合的操作才表示有效的状态变化,这种情况下也是必需创建的。

对于 F# 的记录类型,我们现在就需要了解这些,在第九章我们还要再讨论 .NET 中的函数式数据类型。在下一节,我们将开始讨论一个大型示例程序,这是本章的重点,会涉及表示程序数据的通常方法。

时间: 2024-11-13 09:39:31

7.1.2 C# 中的函数式数据结构的相关文章

Redis 中 5 种数据结构的使用场景介绍

这篇文章主要介绍了Redis中5种数据结构的使用场景介绍,本文对Redis中的5种数据类型String.Hash.List.Set.Sorted Set做了讲解,需要的朋友可以参考下 一.redis 数据结构使用场景 原来看过 redisbook 这本书,对 redis 的基本功能都已经熟悉了,从上周开始看 redis 的源码.目前目标是吃透 redis 的数据结构.我们都知道,在 redis 中一共有5种数据结构,那每种数据结构的使用场景都是什么呢? String——字符串 Hash——字典

浅析Linux驱动模型中的底层数据结构kobject和kset

1.kobject Linux内核用kobject来表示一个内核对象.它和Sysfs文件系统联系密切,在内核中注册到系统中的每个kobject对象在sysfs文件系统中对对应着一个文件目录.kobject数据结构通常的用法是嵌入到其对他的数据结构中(即容器,比如cdev结构),用于实现内核对该类数据结构对象的管理.这些数据结构(容器)通过kobject连接起来,形成了一个树状结构. 它在源码中的定义为: /*<include/linux/kobject.h>*/ struct kobject

游戏中的技能数据结构

问题:游戏中上百个技能是如何储存的,如果调用的,不会是一起加载,if判断一个一个的吧? 回答: 蓝色的字体是我们游戏中的做法 主流的做法是通过 Add Buff 和DeBuff 来实现的,下面简单Buff的释放方式 最简单的Buff需要有如下通用属性: 1.生效时间->在添加到对象上后,作用的时间长度,一般有立即作用,延迟一段时间生效等等 2.作用时间->指该Buff在对象身上作用的时间,生效后立即完全,如普通攻击,还有持续作用的,如中毒后持续扣血,眩晕等等 3.作用对象->某些技能制定

第二章 python中重要的数据结构(下)

二.元组(tuple):不可变序列 跟list一样,也是一种序列,唯一不同的是,元组元素不能被修改,通常用(, ,)表示元组,也可以不加括号. 1 #创建元组 2 >>> 1,2,3 3 (1, 2, 3) 4 >>> t = (1,2,3) 5 >>> t 6 (1, 2, 3) 7 #创建空元组 8 >>> t1 = () 9 >>> t1 10 () 11 #创建只有一个元素的元组,这里注意必须带上逗号 12

Scala 中的函数式编程基础(二)

主要来自 Scala 语言发明人 Martin Odersky 教授的 Coursera 课程 <Functional Programming Principles in Scala>. 2. Higher Order Functions 把其他函数作为参数或者作为返回值,就是 higher order functions,python 里面也可以看到这样使用的情形.在酷壳上的博客有一个例子就是将函数作为返回值. 2.1 匿名函数 在 python 里边叫 lambda 函数,常常与 map(

Python学习(一):入门篇:python中的一些数据结构

Python里的一些基本知识点总结 Last Edit 2014/5/2 这里记录的是Python2.7版本的语法特征,部分与Python3.0是不一样的. 一,关于开发环境 在windows下可以直接在官网下载相关的版本,然后默认安装.使用直带的IDLE编辑器. IDLE中两个有用的快捷键: ALT+P:重复历史命令(从最近到最老) ALT+N:   重复历史命令(从最老到最近) IDLE中没有清屏功能. 在cmd中进行: 1,首先要在环境变量的path中添加相关的路径: C:\Python2

JS函数式编程【译】4.在Javascript中实现函数式编程的技术

?? Functional Programming in Javascript 主目录上一章 建立函数式编程环境 第四章 在Javascript中实现函数式编程的技术 扶好你的帽子,我们现在要真正进入函数式的思想了. 这章我们继续下面的内容: 把所有的核心概念放到一个集中的范式里 探索函数式编程之美 一步步跟踪函数式模式相互交织的逻辑 我们将贯穿整章建立一个简单的应用做一些很酷的事情 你可能已经注意到,在上一章我们介绍Javascript的函数式库的时候引入了一些概念, 而不是在第二章<函数式编

Unity3D中常用的数据结构总结与分析

Unity3D中常用的数据结构总结与分析 c#语言规范 阅读目录 1.几种常见的数据结构 2.几种常见数据结构的使用情景 来到周末,小匹夫终于有精力和时间来更新下博客了.前段时间小匹夫读过一份代码,对其中各种数据结构灵活的使用赞不绝口,同时也大大激发了小匹夫对各种数据结构进行梳理和总结的欲望.正好最近也拜读了若干大神的文章,觉得总结下常用的数据结构以供自己也能灵活的使用变得刻不容缓.那么还是从小匹夫的工作内容入手,就谈谈在平时使用U3D时经常用到的数据结构和各种数据结构的应用场景吧. 回到目录

Android开发中高效的数据结构

android开发中,在java2ee或者android中常用的数据结构有Map,List,Set,但android作为移动平台,有些api(很多都是效率问题)显然不够理想,本着造更好轮子的精神,android团队编写了自己的api用来代替java api SimpleArrayMap<K,V>与ArrayMap<K,V> 实质上ArrayMap继承自SimpleArrayMap,主要是为了实现像HashMap一样的api方法,让习惯使用HashMap的开发者感觉不到差异,本质上是