第八章 异常处理和字符串处理和文件操作

本文详细介绍了Go语言中的错误处理机制,包括error接口的使用、errors包及fmt包的Errorf函数。此外,还讲解了字符串操作,如Contains、Join、Index等函数的使用,以及strconv包中的字符串转换方法。最后,提到了文件操作的基本操作,如打开、写入、读取和删除文件。
摘要由CSDN通过智能技术生成

异常处理

error接口

Go语言引入了一个关于错误处理的标准模式,即error接口,它是Go语言内建的接口类型,该接口的定义如下:

type error interface {
    Error() string
}

Go语言的标准库代码包errors为用户提供如下方法:

package errors

type errorString struct { 
    text string 
}

func New(text string) error { 
    return &errorString{text} 
}

func (e *errorString) Error() string { 
    return e.text 
}

另一个可以生成error类型值的方法是调用fmt包中的Errorf函数:

package fmt
import "errors"

func Errorf(format string, args ...interface{}) error {
    return errors.New(Sprintf(format, args...))
}

示例代码:

import (
    "errors"
    "fmt"
)

func main() {
    var err1 error = errors.New("a normal err1")
    fmt.Println(err1) //a normal err1

    var err2 error = fmt.Errorf("%s", "a normal err2")
    fmt.Println(err2) //a normal err2
}

函数通常在最后的返回值中返回错误信息:

import (
    "errors"
    "fmt"
)

func Divide(a, b float64) (result float64, err error) {
    if b == 0 {
        result = 0.0
        err = errors.New("runtime error: divide by zero")
        return
    }

    result = a / b
    err = nil
    return
}

func main() {
    r, err := Divide(10.0, 0)
    if err != nil {
        fmt.Println(err) //错误处理 runtime error: divide by zero
    } else {
        fmt.Println(r) // 使用返回值
    }
}

panic

在通常情况下,向程序使用方报告错误状态的方式可以是返回一个额外的error类型值。

但是,当遇到不可恢复的错误状态的时候,如数组访问越界、空指针引用等,这些运行时错误会引起painc异常。这时,上述错误处理方式显然就不适合了。反过来讲,在一般情况下,<font color=#FF0000 我们不应通过调用panic函数来报告普通的错误,而应该只把它作为报告致命错误的一种方式。当某些不应该发生的场景发生时,我们就应该调用panic。

一般而言,当panic异常发生时,程序会中断运行,并立即执行在该goroutine(可以先理解成线程,在中被延迟的函数(defer 机制)。随后,程序崩溃并输出日志信息。日志信息包括panic value和函数调用的堆栈跟踪信息。

不是所有的panic异常都来自运行时,直接调用内置的panic函数也会引发panic异常;panic函数接受任何值作为参数。

字符串处理

字符串在开发中经常用到,包括用户的输入,数据库读取的数据等,我们经常需要对字符串进行分割、连接、转换等操作,我们可以通过Go标准库中的strings和strconv两个包中的函数进行相应的操作。

字符串操作

下面这些函数来自于strings包,这里介绍一些我平常经常用到的函数,更详细的请参考官方的文档。

Contains

func Contains(s, substr string) bool
功能:字符串s中是否包含substr,返回bool

示例代码:

    fmt.Println(strings.Contains("seafood", "foo"))
    fmt.Println(strings.Contains("seafood", "bar"))
    fmt.Println(strings.Contains("seafood", ""))
    fmt.Println(strings.Contains("", ""))
    //运行结果:
    //true
    //false
    //true
    //true

Join

func Join(a []string, sep string) string
功能:字符串链接,把slice a通过sep链接起来

示例代码:

    s := []string{"foo", "bar", "baz"}
    fmt.Println(strings.Join(s, ", "))
    //运行结果:foo, bar, baz

Index

func Index(s, sep string) int
功能:在字符串s中查找sep所在的位置,返回位置值,找不到返回-1

示例代码:

    fmt.Println(strings.Index("chicken", "ken"))
    fmt.Println(strings.Index("chicken", "dmr"))
    //运行结果:
    //    4
    //    -1

Repeat

func Repeat(s string, count int) string
功能:重复s字符串count次,最后返回重复的字符串

示例代码:

    fmt.Println("ba" + strings.Repeat("na", 2))
    //运行结果:banana

Replace

func Replace(s, old, new string, n int) string
功能:在s字符串中,把old字符串替换为new字符串,n表示替换的次数,小于0表示全部替换

示例代码:

    fmt.Println(strings.Replace("oink oink oink", "k", "ky", 2))
    fmt.Println(strings.Replace("oink oink oink", "oink", "moo", -1))
    //运行结果:
    //oinky oinky oink
    //moo moo moo

Split

func Split(s, sep string) []string
功能:把s字符串按照sep分割,返回slice

示例代码:

    fmt.Printf("%q\n", strings.Split("a,b,c", ","))
    fmt.Printf("%q\n", strings.Split("a man a plan a canal panama", "a "))
    fmt.Printf("%q\n", strings.Split(" xyz ", ""))
    fmt.Printf("%q\n", strings.Split("", "Bernardo O'Higgins"))
    //运行结果:
    //["a" "b" "c"]
    //["" "man " "plan " "canal panama"]
    //[" " "x" "y" "z" " "]
    //[""]

Trim

func Trim(s string, cutset string) string
功能:在s字符串的头部和尾部去除cutset指定的字符串

示例代码:

    fmt.Printf("[%q]", strings.Trim(" !!! Achtung !!! ", "! "))
    //运行结果:["Achtung"]

Fields

func Fields(s string) []string
功能:去除s字符串的空格符,并且按照空格分割返回slice

示例代码:

    fmt.Printf("Fields are: %q", strings.Fields("  foo bar  baz   "))
    //运行结果:Fields are: ["foo" "bar" "baz"]

字符串转换

字符串转化的函数在strconv中,如下也只是列出一些常用的。

Append

Append 系列函数将整数等转换为字符串后,添加到现有的字节数组中。

    str := make([]byte, 0, 100)
    str = strconv.AppendInt(str, 4567, 10) //以10进制方式追加
    str = strconv.AppendBool(str, false)
    str = strconv.AppendQuote(str, "abcdefg")
    str = strconv.AppendQuoteRune(str, '单')

    fmt.Println(string(str)) //4567false"abcdefg"'单'

Format

Format 系列函数把其他类型的转换为字符串。
示例代码:

	a := strconv.FormatBool(false)
    b := strconv.FormatInt(1234, 10)
    c := strconv.FormatUint(12345, 10)
    d := strconv.Itoa(1023)

    fmt.Println(a, b, c, d) //false 1234 12345 1023

Parse

Parse 系列函数把字符串转换为其他类型。
示例代码:

package main

import (
    "fmt"
    "strconv"
)

func checkError(e error) {
    if e != nil {
        fmt.Println(e)
    }
}
func main() {
    a, err := strconv.ParseBool("false")
    checkError(err)
    b, err := strconv.ParseFloat("123.23", 64)
    checkError(err)
    c, err := strconv.ParseInt("1234", 10, 64)
    checkError(err)
    d, err := strconv.ParseUint("12345", 10, 64)
    checkError(err)
    e, err := strconv.Atoi("1023")
    checkError(err)
    fmt.Println(a, b, c, d, e) //false 123.23 1234 12345 1023
}

文件操作

建立与打开文件

新建文件可以通过如下两个方法:

func Create(name string) (file *File, err Error)
根据提供的文件名创建新的文件,返回一个文件对象,默认权限是0666的文件,返回的文件对象是可读写的。

func NewFile(fd uintptr, name string) *File
根据文件描述符创建相应的文件,返回一个文件对象

通过如下两个方法来打开文件:

func Open(name string) (file *File, err Error)
该方法打开一个名称为name的文件,但是是只读方式,内部实现其实调用了OpenFile。

func OpenFile(name string, flag int, perm uint32) (file *File, err Error)
打开名称为name的文件,flag是打开的方式,只读、读写等,perm是权限

写文件

func (file *File) Write(b []byte) (n int, err Error)
写入byte类型的信息到文件

func (file *File) WriteAt(b []byte, off int64) (n int, err Error)
在指定位置开始写入byte类型的信息

func (file *File) WriteString(s string) (ret int, err Error)
写入string信息到文件

读文件

func (file *File) Read(b []byte) (n int, err Error)
读取数据到b中

func (file *File) ReadAt(b []byte, off int64) (n int, err Error)
从off开始读取数据到b中

删除文件

func Remove(name string) Error
调用该函数就可以删除文件名为name的文件

案例:拷贝文件

示例代码:

package main

import (
    "fmt"
    "io"
    "os"
)

func main() {
    args := os.Args //获取用户输入的所有参数

    //如果用户没有输入,或参数个数不够,则调用该函数提示用户
    if args == nil || len(args) != 3 {
        fmt.Println("useage : xxx srcFile dstFile")
        return
    }

    srcPath := args[1] //获取输入的第一个参数
    dstPath := args[2] //获取输入的第二个参数
    fmt.Printf("srcPath = %s, dstPath = %s\n", srcPath, dstPath)

    if srcPath == dstPath {
        fmt.Println("源文件和目的文件名字不能相同")
        return
    }

    srcFile, err1 := os.Open(srcPath) //打开源文件
    if err1 != nil {
        fmt.Println(err1)
        return
    }

    dstFile, err2 := os.Create(dstPath) //创建目的文件
    if err2 != nil {
        fmt.Println(err2)
        return
    }

    buf := make([]byte, 1024) //切片缓冲区
    for {
        //从源文件读取内容,n为读取文件内容的长度
        n, err := srcFile.Read(buf)
        if err != nil && err != io.EOF {
            fmt.Println(err)
            break
        }

        if n == 0 {
            fmt.Println("文件处理完毕")
            break
        }

        //切片截取
        tmp := buf[:n]
        //把读取的内容写入到目的文件
        dstFile.Write(tmp)
    }

    //关闭文件
    srcFile.Close()
    dstFile.Close()
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值