2.4.1.实现一个简单的Statistics函数
为方便起见,我们创建了一个聚合类型用于保存用户输入的数据以及我们的两个统计结果。
1 2 3 4 5 | type statistics struct { numbers []float64 mean float64 median float64 } |
Go的结构体类似于C语言的结构体或者Java里只有public数据成员且没有方法的类,但是不像C++语言的结构体那样,因为它并不是一个类。正如我们将要看到的,Go语言的结构体对聚合和嵌入提供非常出色的支持,这是Go语言面向对象编程的核心。
1 2 3 4 5 6 7 | func getStats(numbers []float64) (stats statistics) { stats.numbers = numbers sort.Float64s(stats.numbers) stats.mean = sum(numbers) / float64(len(numbers)) stats.median = median(numbers) return stats } |
该函数接受一个数值切片(这种情况下由processRequest() 函数获得),并将相应的值填充到stats结果变量中。为了计算median,我们需要将切片升序排序,这里使用了sort包里的Float64s()函数,该函数可以对[]float64切片进行原地排序。这意味着getstats()函数修改了它的参数,这种将切片、引用或者指针以参数的形式传递给函数是很常见的。如果我们想要保留原始切片,我们可以使用Go语言内置的copy ()函数将其赋值给一个临时切片变量,并在函数中使用该临时切片。
mean(平均数)是一连串数值之和除以数值的个数。这里我们使用了一个辅助函数来计算数值切片之和,将切片的长度(数值的个数)转换为float64类型以使类型兼容(因为sum()返回一个float64类型的值)。同时我们还可以确保这是一个浮点除法运算并避免了使用整数类型时发生的截断问题。median是用来保存中位数的,我们使用median()函数来计算它。
我们还没有检查被零除的情况,因为我们的程序逻辑被设计为当getStats() 函数至少有一个数值时才会被调用;所以如果我们不修改逻辑,程序将产生运行时异常并终止运行。对于一个任务关键型应用程序来说,当出现问题时程序决不应被终止,我们可以使用Go语言的recover()函数来捕获异常,并将其恢复到正常状态以使程序继续运行。
1 2 3 4 5 6 | func sum(numbers []float64) (total float64) { for _, x := range numbers { total += x } return total } |
该函数使用了一个for…range循环来遍历切片中的所有数值并计算它们的和。Go语言总是将所有变量初始化为0,包括已命名的要返回的值。
1 2 3 4 5 6 7 8 | func median(numbers []float64) float64 { middle := len(numbers) / 2 result := numbers[middle] if len(numbers)%2 == 0 { result = (result + numbers[middle-1]) / 2 } return result } |
该函数接受一个已排好序的float64类型的切片,并将中位数赋值给middle变量,但是如果切片个数是偶数,就会产生两个中间数,所以在这种情况下我们计算这两个中间数的和并处以2的值作为中位数,并在函数结尾返回该值。
在本小节中,我们讲解了该程序最主要的几个处理过程,在下一小节我们将演示一个只有一个页面的web程序的基本实现。(那些对web编程不感兴趣的读者可以略过本节直接跳到练习或者下一章。)