分享

排序,使用函数自定义排序,Panic,Defer

 心平9bwburua3p 2017-04-14

排序

代码实例

// 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)
}

运行程序

# 运行程序,打印排序好的字符串和整形序列以及我们 `AreSorted`
# 测试的结构 `true`。
$ go run sorting.go
Strings: [a b c]
Ints:    [2 4 7]
Sorted:  true

使用函数自定义排序

代码实例

// 有时候我们想使用和集合的自然排序不同的方法对集合进行排序。
// 例如,我们想按照字母的长度而不是首字母顺序对字符串排序。
// 这里是一个 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)
}

运行程序

# 运行这个程序,和预期的一样,显示了一个按照字符串
# 长度排序的列表。
$ go run sorting-by-functions.go 
[kiwi peach banana]

# 类似的,参照这个创建一个自定义类型的方法,实现这个类型的
# 这三个接口方法,然后在一个这个自定义类型的集合上调用 
# `sort.Sort` 方法,我们就可以使用任意的函数来排序 Go 切片了。

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)
    }
}

运行程序

# 运行程序将会引起 panic,输出一个错误消息和 Go 运行时
# 栈信息,并且返回一个非零的状态码。
$ go run panic.go
panic: a problem

goroutine 1 [running]:
main.main()
    /.../panic.go:12 +0x47
...
exit status 2

# 注意,不像有些语言中处理多个错误那样,在 Go 中习惯使用错
# 误码返回任意可能的值。

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()
}

运行程序

# 执行程序,确认这个文件在写入后是已关闭的。
go run defer.go
creating
writing
closing
动手实践是学习 IT 技术最有效的方式! 开始实验

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多