4.3 创建控制台应用程序

728 篇文章 1 订阅
349 篇文章 0 订阅

4.3 创建控制台应用程序

 

为我们的应用程序写一个简单的、基于控制台的输出,是一个良好的开始,因为这做起来相对容易,并且很快能看到结果。我们在本节将使用的几项技术,在稍后的图形版本中也很重要;即使应用程序不需要基于控制台的输出,仍可以把它作为起点,到后来把它改编成更高级的图形化版本。在这一章,我们就要这样做。

在上一节,我们已经完成了大部分程序,通过编写通用的泛函数,控制台和图形化版本都要使用。函数 processLines,把从 CSV 文件加载的字符串列表作为参数,返回解析后的元组列表;函数 calculateSum,对数据集中的数值求和。在清单 4.4 中,还有一个计算百分比的等式,因此,唯一剩余的任务是从文件中读数据,和输出到控制台。在清单 4.5 中可以看到我们如何把这一切放到一起。

 

清单 4.5 把所有基本控制台的版本放到一起 (F# Interactive)

> open System.IO;;

 

> let lines =List.ofseq(File.ReadAllLines(@"C:\Ch03\data.csv"));;  [1]

val lines : string list

 

> let data = processLines(lines);;  <-- 把所有行转换成元组列表

val data : (string * int) list =

  [("Asia",3634); ("Australia/Oceania", 30); ("Africa", 767);

   ("SouthAmerica", 511); ("Europe", 729); ("North America",307)]

 

> let sum = float(calculateSum(data));;  <-- 对数值求和

val sum : float = 5978.0

 

> for (title, value) in data do  [2]

   letpercentage = int((float(value)) / sum * 100.0) | 计算百分比,

   Console.WriteLine("{0,-18}- {1,8} ({2}%)",        | 输出

                   title, value, percentage)      |

;;

Asia               -     3634 (60%)

Australia/Oceania    -       30 (0%)

Africa              -      767 (12%)

South America       -      511 (8%)

Europe             -      729 (12%)

North America       -      307(5%)

 

清单 4.5 首先打开 System.IO 命名空间,这里有处理文件系统的 .NET 类;接下来,使用这个命名空间下的类 File 和它的方法 ReadAllLines[1],提供一种简单方式读取文件的文本内容,返回字符串数组;再次,使用 ofseq 函数把字符串数组转换成列表;接下来的两步很容易,因为使用了我们在上一节已经实现并测试过的两个函数,处理所有的文本行,并对结果求和。

我们现在再看最后一段代码[2],使用 for 循环遍历解析后的数据集中的所有元素。它类似于 C# 中的 foreach 语句,在关键字 for 和 in 之间的表达式不仅是变量,还是模式。可以发现,在 F# 中,模式匹配比你想象的要更常见!这一特殊模式把元组分解成标题(值 title)和数值(value)。在循环体中,我们首先使用在清单 4.4 中测试过的等式,计算出百分比,然后,使用我们熟悉的.NET 方法 Console.WriteLine 输出结果。

 

F# 和 .NET 格式化字符串

 

在 F# 中,有两种方法来解决字符串格式化的问题。一种是使用 F# 库中的函数,这与 F# 的前辈(OCaml 语言)是兼容的,也很好地适用 F#;另一种是使用 .NET 框架中的函数,它有时比对应的 F# 函数更丰富。曾经在以前的示例中用过的printfn 函数,代表第一种方法,而清单最后的 Console.WriteLine 则是标准的 .NET 方法。

在 .NET 中格式化字符串,需要指定复合格式字符串(composite format string)作为第一个参数,它包含占位符,由后面的参数值填充。占位符包含参数值的索引,还可指定对齐方式和格式。两种最常用的格式化方法是 Console.WriteLine(用于输出到控制台)和 String.Format(返回格式化的字符串):

 

> let name, date = "Tomas",DateTime.Now;;

> let s = String.Format("Hello {0}!Today is: {1:D}", name, date);;

val s : string = "Hello Tomas! Todayis: Sunday, 15 March 2009"

 

格式化字符串放在冒号后面,例如,{0:D} 表示用长日期格式,{0:e} 表示科学计数法的浮点数,{0: x} 表示十六进制整数。在上面的清单中,我们还指定对齐方式和充填打印值,用在逗号之后加上数字表示:

 

> Console.WriteLine("Number withspaces: {0,10}!", 42);;

Number with spaces: 42!

> Console.WriteLine("Number withspaces: {0,-10}!", 42);;

Number with spaces: 42 !

 

除了对齐方式和充填值的规范之外,当格式化 .NET 标准的数据类型(例如,DateTime 类型或 DateTimeOffset 类型,表示相对于 UTC 时区的时间)时,F# 还经常使用 .NET 库。下面的示例汇总了一些有用的格式化字符串。注意,输出因区域而异,因此,实际输出可能不同,取决于你的系统设置:

 

> let date = DateTimeOffset.Now;;

val date : DateTimeOffset = 03/15/200916:37:53 +00:00

> String.Format("{0:D}",date);;

val it : string = "Sunday, 15 March2009"

> String.Format("{0:T}",date);;

val it : string = "16:36:09"

>String.Format("{0:yyyy-MM-dd}", date);;

val it : string = "2009-03-15"

 

F# 格式化字符串的专有函数,会被编译器特别处理,好处是可以检查出使用的类型是否正确。就像在 .NET 中的格式化一样,第一个参数指定格式,但在格式中占位符指定参数值的类型;没有索引,因此,占位符必须与作为参数值的顺序相同。在 F# 中,经常会使用 printf 和 printfn 输出字符串到控制台,(printfn 多一个换行符), sprintf 返回格式化的字符串:

 

printfn "Hello %s! Today is: %A"name date

let s = sprintf "Hello %s! Today is:%A" name date

 

下面的清单是最常用的占位符类型:

■ %s:参数值是 string 类型。

■ %d:有符号或无符号的整数类型(例如,byte、int 或 ulong)

■ %f:float 或 float32 类型的浮点数

■ %A:输出任意类型的值,使用 F# 反射和 .NET ToString 方法的组合,打印出任何值的大多数可读的调试信息。

想在 .NET 和 F# 的方法之间作出选择,有时是困难的。一般情况下,使用 F# 函数通常更好一些,因为,它就是为了很好地使用 F# 而设计的,而且,能够利用格式字符串检查参数值的类型。如果 F# 中没有所需要的功能,或使用 F# 函数很难实现,就可以转到 .NET 格式化方法,因为,两者在 F# 中都可以很方便地使用。

 

如果不打算在 F# Interactive 中运行,可以把清单 4.5 的代码转换成标准的控制台程序。只要用 Visual Studio 写代码,通过按 Alt + Enter 在 F# Interactive 中运行,那么,就已经有了应用程序完整的源代码。为使程序更有用,唯一要改变是增加从命令行中读文件名的能力。在 F# 中读命令行参数,可以使用标准的 .NET 的 Environment.GetCommandLineArgs 方法;或者可以写入口点(entry-point)函数,取字符串数组作为参数值,并使用 EntryPoint 属性值标记。数组中的第一个元素是运行的可执行文件的名称,因此,读第一个参数值,可以写成 args.[1]。

在这一节,我们给数据处理程序添加了一个简单的基于控制台的输出。下面,将要用 Windows Forms 库实现图形用户界面,然后,再用 System.Drawing 命名空间中的类绘制饼图。由于有了前面的实验以及在开发展期间使用了 F# Interactive,我们已经知道代码的重要部分工作正常。如果我们打算从零开始写整个应用程序,在代码中很可能会有几个小的,但很难发现的错误。当然,在开发过程的后期,我们应该把互动式的实验转变成单元测试,这个话题会在第十一章讨论。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值