排序
Go 的 sort
包实现了内置和用户自定义数据类型的排序功能,首先关注内置数据类型的排序。
package main
import "fmt"
import "sort"
func main() {
// 排序方法是正对内置数据类型的;这里是一个字符串的例子。
// 注意排序是原地更新的,所以他会改变给定的序列并且不返回
// 一个新值。
strs := []string{"c", "a", "b"}
sort.Strings(strs)
fmt.Println("Strings:", strs)
// 一个 `int` 排序的例子。
ints := []int{7, 2, 4}
sort.Ints(ints)
fmt.Println("Ints: ", ints)
// 我们也可以使用 `sort` 来检查一个序列是不是已经
// 是排好序的。
s := sort.IntsAreSorted(ints)
fmt.Println("Sorted: ", s)
}
函数自定义排序
有时候我们想使用和集合的自然排序不同的方法对集合进行排序。例如,我们想按照字母的长度而不是首字母顺序对字符串排序。这里是一个 Go 自定义排序的例子。
package main
import "sort"
import "fmt"
// 为了在 Go 中使用自定义函数进行排序,我们需要一个对应的
// 类型。这里我们创建一个为内置 `[]string` 类型的别名的
// `ByLength` 类型,
type ByLength []string
// 我们在类型中实现了 `sort.Interface` 的 `Len`,`Less`
// 和 `Swap` 方法,这样我们就可以使用 `sort` 包的通用
// `Sort` 方法了,`Len` 和 `Swap` 通常在各个类型中都差
// 不多,`Less` 将控制实际的自定义排序逻辑。在我们的例
// 子中,我们想按字符串长度增加的顺序来排序,所以这里
// 使用了 `len(s[i])` 和 `len(s[j])`。
func (s ByLength) Len() int {
return len(s)
}
func (s ByLength) Swap(i, j int) {
s[i], s[j] = s[j], s[i]
}
func (s ByLength) Less(i, j int) bool {
return len(s[i]) < len(s[j])
}
// 一切都准备好了,我们现在可以通过将原始的 `fruits` 切片转型成 `ByLength` 来实现我们的自定排序了。然后对这个转型的切片使用 `sort.Sort` 方法。
func main() {
fruits := []string{"peach", "banana", "kiwi"}
sort.Sort(ByLength(fruits))
fmt.Println(fruits)
}
Panic
panic
意味着有些出乎意料的错误发生。通常我们用它来表示程序正常运行中不应该出现的,或者我们没有处理好的错误。
package main
import "os"
func main() {
// 我们将在真个网站中使用 panic 来检查预期外的错误。这个
// 是唯一一个为 panic 准备的例子。
panic("a problem")
// panic 的一个基本用法就是在一个函数返回了错误值但是我们并不知道(或
// 者不想)处理时终止运行。这里是一个在创建一个新文件时返回异常错误时的
// `panic` 用法。
_, err := os.Create("/tmp/file")
if err != nil {
panic(err)
}
}
Defer
Defer
被用来确保一个函数调用在程序执行结束前执行,同样用来执行一些清理工作,defer
用在像其他语言中的 ensure 和 finally 用到的地方。
package main
import "fmt"
import "os"
// 假设我们想要创建一个文件,向它进行写操作,然后在结束
// 时关闭它。这里展示了如何通过 `defer` 来做到这一切。
func main() {
// 在 `closeFile` 后得到一个文件对象,我们使用 defer
// 通过 `closeFile` 来关闭这个文件。这会在封闭函数
// (`main`)结束时执行,就是 `writeFile` 结束后。
f := createFile("/tmp/defer.txt")
defer closeFile(f)
writeFile(f)
}
func createFile(p string) *os.File {
fmt.Println("creating")
f, err := os.Create(p)
if err != nil {
panic(err)
}
return f
}
func writeFile(f *os.File) {
fmt.Println("writing")
fmt.Fprintln(f, "data")
}
func closeFile(f *os.File) {
fmt.Println("closing")
f.Close()
}