9.1.2 使用类型扩展追加成员
来源:互联网 发布:ppt图表数据不能修改 编辑:程序博客网 时间:2024/06/07 06:25
9.1.2 使用类型扩展追加成员
在上一节我们提到过,可以为任何 F# 数据类型添加成员;现在,我们将使用差别联合来演示。这种种方法能够添加成员,而不需要修改任何原始代码。这样,我们将能够保留原始类型和原始的函数声明,不作修改,然后添加成员。
我们将扩展第五章声明 schedule 类型的示例,这个类型表示的事件可以只发生一次,或重复发生,或从不发生。除了数据类型之外,我们还创建了计算事件下一次发生时间的函数。清单 9.4 是代码稍作修改后的版本,我们使代码更紧凑,并使用简单的工具函数,重构了模式匹配中的 Once 分支;如果想比较的话,原始代码在清单 5.5 中。
清单 9.4 有函数的Schedule 数据类型 (F#)
type Schedule = [1] <-- 声明原始类型
| Never
| Once of DateTime
| Repeatedly of DateTime * TimeSpan
let futureOrMaxValue(dt) = [2] <-- 实现工具函数
if (dt > DateTime.Now) then dtelse DateTime.MaxValue
let getNextOccurrence(schedule) = [3] <-- 指定公开的行为
match schedule with
| Never ->DateTime.MaxValue
| Once(eventDate) ->futureOrMaxValue(eventDate)
| Repeatedly(startDate, interval)–>
let secondsFromFirst =(DateTime.Now - startDate).TotalSeconds
let q = max(secondsFromFirst / interval.TotalSeconds) 0.0
startDate.AddSeconds
(interval.TotalSeconds * (Math.Floor(q) + 1.0))
最重要的变化是,我们增加了工具函数 futureOrMaxValue[2]。这个改变并不显著提高可读性,只是用来说明有这种选择。在一个更复杂的项目中,肯定会有一些工具函数。
这个观点就是,在典型的 F# 源文件中,首先声明类型,然后,有一堆工具(私有)函数,再后是我们想要公开为成员的函数[3]。如果我们想利用上一节介绍的方法,把最后的函数变为成员,这是相当困难的。因为成员必须是类型声明的一部分,但是,我们通常想把工具函数放在类型和其成员之间!
要解决这个问题,需要使用固有类型扩展(intrinsic type extensions),它能够为在文件中先声明的类型,添加成员。清单 9.5 显示了我们如何能够为schedule 类型使用扩展。
清单 9.5 利用固有类型扩展添加成员 (F#)
type Schedule =
| Never
| Once of DateTime
| Repeatedly of DateTime *TimeSpan
let futureOrMaxValue(dt) =
(...)
let getNextOccurrence(schedule) = [1]
(...)
type Schedule with [2]
member x.GetNextOccurrence() =getNextOccurrence(x) [3]
member x.OccursNextWeek = | [4]
getNextOccurrence(x)< DateTime.Now.AddDays(7.0) |
对比清单 9.4 的代码,大部分没有改变,为了简洁,所以就省略了;唯一增加的是最后四行代码。第一行[2]定义了类型扩展,告诉 F# 编译器,要把后面的成员添加到指定名字的类型;后面就是正常的成员声明。因为我们已经把核心功能实现为函数[1],成员的实现就简单了[3]。除了得到下一次发生的时间以外,我们还增加了一个属性[4],使用私有函数检查下一次发生的时间是否就在接下来的一周。
如果学过 C# 3.0,就会发现类型扩展和扩展方法之间有相似性。使用类型扩展,可以为其他程序集中现有类型添加方法和属性。前一个清单的情况有所不同,因为我们使用了固有类型扩展。这是一种特殊的情况,即,声明原始类型和扩展在同一个文件中;在这种情况下,F# 编译器会把类型的两部分合并到同一个类中,我们也能访问在类型扩展中类型的私有成员。
清单 9.6 演示了调用清单 9.5 中的成员。使用类型扩展添加的成员,其行为与其他成员一样的,因此,清单没有任何意外惊喜。
清单 9.6 使用成员处理 Schedule (F# Interactive)
> let sch = Repeatedly(DateTime.Now,TimeSpan(2, 0, 0, 0));;
val sch : Schedule
> sch.OccursNextWeek();; <-- 使用重复事件进行测试
val it : bool = true
> let sch = Never;;
val sched : Schedule
> sch.OccursNextWeek();; <-- 测试无计划事件的行为
val it : bool = false
正如我们处理记录时,通常的方法是创建 F# 值;对于在我们示例中的差别联合,就是使用 Repeatedly 或 Never 识别器(我们还可以使用 Once 识别器)。我们有了值以后,就可以使用面向对象的点符号调用它的成员。
正如我们刚看到的,在写成熟代码时,成员是非常有用的,因为它可以把代码包装成结构良好的片断,以方便使用类型。在 F# 的开发过程中,我们通常不首先写有成员的代码,只有代码测试通过以后,才添加成员,API 设计就固定了。我们已经讨论过添加成员的两种方法:
■类型足够简单时,直接在类型声明中追加成员。
■对于复杂的类型,使用固有类型扩展,可以少改变代码。
类型扩展还有一个好处,可以在扩充之前,使用 F# Interactive 工具,测试类型和它的处理函数,因为我们不必一口气声明整个类型。
我们已经知道了,对于把以数据为中心的 F# 代码转变成实际的 .NET 应用程序或组件,成员是非常重要的。现在,我们将把注意力转向以行为中心的应用程序。
- 9.1.2 使用类型扩展追加成员
- 使用类的类型成员
- 追加文件:使用FileWriter
- extend(扩展)和append(追加)的区别
- 9.1.1 添加成员到 F# 类型
- 使用C语言编写Python扩展——创建自定义类型(2)
- 使用反射调用类型成员 方法,字段,属性
- 在C++中使用引用类型的成员变量
- 4--4数组做数据成员(扩展2,3)
- 4-4数组做数据成员(扩展2)
- 成员函数指针和其他类型的强制转换,使用一般指针调用成员函数
- Magento 2 创建或扩展配置类型
- Logminer使用(追加日志模式)
- 使用jquery追加table行
- 使用扩展方法,向现有类型“添加”方法
- 建议101:使用扩展方法,向现有类型“添加”方法
- 【c++笔记七】教你使用"const类型的对象、成员函数"和"static类型的成员函数、变量"
- 8.2.2 追加字符串
- Bmp学习
- oozie常见问题
- 在ACM中使用QuerySpec进行联合查询的示例
- Oracle 5种索引访问方式浅析
- php 读取xml的方法 (iconv解决中文乱码问题)
- 9.1.2 使用类型扩展追加成员
- oralce查看数据库表空间信息
- sql server转换时间函数 转成 xxx年xx月xx日格式
- android模拟器Genymotion 连接eclipse项目
- Linux创建、删除文件和文件夹命令
- Set的底层实现方式
- STC15F204 模拟串口例程 简单理解
- js 弹出框、弹出层
- hdoj 1002 A+B Problem II