• Go(一)基础知识


    一、第一个程序

    基本程序结构

    package main // 包
    
    import "fmt" // 引入依赖代码
    
    // 功能实现
    func main() { fmt.Println("hello world!") }

    注意点:

    1.应用程序入口

    • 必须是main包:package main
    • 必须是main方法:func main()
    • 文件名不一定是main.go

    2.退出返回值

    与其他主要编程语言的差异

    • Go中main函数不支持任何返回值
    • 通过os.Exit来返回状态

    3.获取命令行参数

    main函数不支持传入参数

    func main()

    在程序中直接通过os.Args获取命令行参数

    编写测试文件

    源码文件以_test结尾:xxx_test.go

    测试方法名以Test开头:func TestXXX(t *testing.T){...}

    package try_test
    
    import "testing"
    
    func TestFirstTry(t *testing.T)  {
    
        t.Log("My first try!")
    
    }

    结果

    === RUN   TestFirstTry
    --- PASS: TestFirstTry (0.00s)
        first_test.go:7: My first try!
    PASS

    Fibonacci数列

    package try
    
    import (
        "fmt"
        "testing"
    )
    
    func TestFibList(t *testing.T)  {
        var a int = 1
        var b int = 1
    
        //var{
        // 可以省略int,类型推断
        //    a int = 1
        //    b int = 1
        //}
        // 类型推断,初试化
        //a := 1
        //b := 1
        fmt.Print(a, " ")
        for i:=0;i<5;i++{
            fmt.Print(" ", b)
            tmp:=a
            a=b
            b=tmp+a
        }
        fmt.Println()
    }

    二、变量、常量、数据类型和运算符

    变量赋值

    与其他主要编程语言的差异

    赋值可以进行自动推断

    在一个赋值语句中可以对多个变量进行同时赋值

    func TestExchage(t *testing.T){
        a := 1
        b := 1
        //tmp := a
        //a = b
        //b = tmp
        a, b= b, a
        t.Log(a, b)
    }

    常量定义

    与其他主要编程语言的差异

    快速设置连续值

    const (
        Monday = iota + 1
        Tuesday
        Wednesday
        Thrusday
        Friday
        Saturday
        Sunday
    )
    
    const (
        Open = 1 << iota
        Close
        Pending
    ) 

    例子

    package _const
    
    import "testing"
    
    const (
        Monday = iota + 1
        Tuesday
        Wednesday
    )
    
    const(
        Readable = 1<<iota
        Writable
        Executable
    )
    
    func TestConstantTry(t *testing.T)  {
        t.Log(Monday, Tuesday, Wednesday)
    } // 1,2,3
    
    func TestConstantTry1(t *testing.T)  {
        a := 7 // 0111
        t.Log(a&Readable==Readable, a&Writable==Writable, a&Executable==Executable)
    } // true,true,true

    数据类型

    基本数据类型

    类型转化

    与其他主要编程语言的差异

    1.Go语言不允许隐式类型转换

    2.别名和原有类型也不能进行隐式类型转换

    package type_test
    
    import "testing"
    
    type MyInt int64
    
    func TestImplict(t *testing.T)  {
        var a int = 1
        var b int64
        //b = a // 不支持隐式类型转换
        b = int64(a)
        t.Log(a, b)
        var c MyInt
        // c = b // 别名的隐式类型转换也不支持
        c = MyInt(b)
        t.Log(a, b, c)
    }

    类型的预定义值

    指针类型

    与其他主要编程语言的差异

    1.不支持指针运算

    func TestPoint(t *testing.T)  {
        a := 1
        aPtr := &a
        t.Log(a, aPtr)
        t.Logf("%T %T", a, aPtr)
        //aPtr = aPtr + 1 // 出错,不支持指针运算
    }


    结果

    === RUN TestPoint
    --- PASS: TestPoint (0.00s)
    type_test.go:22: 1 0xc04205e290
    type_test.go:23: int *int
    PASS

    2.string是值类型,其默认初试化值为空字符串,而不是nil

    func TestString(t *testing.T)  {
        var s string
        t.Log("*"+s+"*")
        t.Log(len(s))
    }
    
    结果
    === RUN   TestString
    --- PASS: TestString (0.00s)
        type_test.go:29: **
        type_test.go:30: 0
    PASS

    运算符

    算术运算符

    比较运算符

    用==比较数组

    • 相同维数且含有相同个数元素的数组才可以比较
    • 每个元素都相同的才相等

    逻辑运算符

    位运算符

    与其他主要编程语言的差异

    三、编写结构化程序

    for循环

    和其他主要编程语言的差异

     示例

    实例

    func TestWhileLoop(t *testing.T)  {
        n := 0
        for n < 5{
            t.Log(n)
            n++
        }
    }
    
    
    结果
    === RUN   TestWhileLoop
    --- PASS: TestWhileLoop (0.00s)
        type_test.go:36: 0
        type_test.go:36: 1
        type_test.go:36: 2
        type_test.go:36: 3
        type_test.go:36: 4
    PASS

    if条件

     与其他编程语言的差异

    • condition表达式结果必须为布尔值
    • 支持变量赋值
    if var declaration; condition {
        // code to be executed if condition is true
    }
    func TestIfMultiSec(t *testing.T)  {
        if a := 1 == 1;a {
            t.Log("1==1")
        }
    }
    
    // a是true,所以执行括号里内容
    
    
    结果
    === RUN   TestIfMultiSec
    --- PASS: TestIfMultiSec (0.00s)
        type_test.go:43: 1==1
    PASS

     switch条件

     与其他主要编程语言的差异

    • 条件表达式不限制为常量或整数
    • 单个case中,可以出现多个结果选项,使用逗号分隔
    • 与C等规则相反,Go语言不需要用break来明确退出一个case
    • 可以不设定switch之后的条件表达式,在此情况下,整个switch结构与多个if...else...的逻辑作用等同

    可以有多个选项

    func TestSwitchMultiCase(t *testing.T)  {
        for i := 0; i < 5; i++{
            switch i {
            case 0, 2:
                t.Log("Even")
            case 1,3:
                t.Log("Odd")
            default:
                t.Log("It is not 0-3")
            }
        }
    }

    相当于if...else...使用

    func TestSwitchCaseCondition(t *testing.T)  {
        for i := 0; i < 5; i++ {
            switch  {
            case i%2 == 0:
                t.Log("Even")
            case i%2 == 1:
                t.Log("Odd")
            default:
                t.Log("unknow")
            }
        }
    }

    四、数组和切片

     数组的声明

     数组元素遍历

    与其他主要编程语言的差异

    数组截取

    切片内部结构

    切片声明

    切片共享存储结构

    数组vs切片

    • 容量是否可伸缩
    • 是否可以进行比较

    五、Map

     Map声明

    Map元素访问

    与其他主要编程语言的差异

    Map遍历

     Map与工厂模式

    • Map的value可以是一个方法
    • 与Go的Dock type接口方式一起,可以方便实现单一方法对象的工厂模式

    实现Set

     

    六、字符串

     与其他主要编程语言的差异

     Unicode UTF8

    编码与存储

    常用字符串函数

    package main
    
    import (
        "fmt"
        "strings"
    )
    
    func main() {
        var s string = "hello go"
        //判断字符串s是否包含子串
        r := strings.Contains(s, "go")
        fmt.Println(r) //true
    
        var s1 []string = []string{"1", "2", "3", "4"}
        //将一系列字符串连接为一个字符串,之间用sep来分隔
        s2 := strings.Join(s1, ",")
        fmt.Println(s2) //1,2,3,4
    
        //子串sep在字符串s中第一次出现的位置,不存在则返回-1
        n1 := strings.Index(s, "go")
        fmt.Println(n1) //6
    
        //返回count个s串联的字符串
        s3 := strings.Repeat(s, 2)
        fmt.Println(s3) //hello gohello go
    
        //返回将s中前n个不重叠old子串都替换为new的新字符串,如果n<0会替换所有old子串
        s4 := strings.Replace(s, "o", "e", -1)
        fmt.Println(s4) //helle ge
    
        //字符串切割,如果后一个参数为空,则按字符切割,返回字符串切片
        s5 := strings.Split(s, " ")
        fmt.Println(s5) //[hello go]
    
        //切除字符串两端的某类字符串
        s6 := strings.Trim(s, "o")
        fmt.Println(s6) //hello g
    
        //去除字符串的空格符,并且按照空格分割返回slice
        s7 := " hello go "
        s8 := strings.Fields(s7)
        fmt.Println(s8) //[hello go]
    }

     七、文件读写

    文件读写

    创建文件 Ceate :文件不存在创建,文件存在,将文件内容清空

        参数:name,打开文件的路径,可以是绝对路径和相对路径

    func main() {
    
        file, err := os.Create("./hello.txt")
        if err != nil {
            fmt.Println("Create error:", err)
            return
        }
        defer file.Close()
    
        fmt.Println("succes!")
    
    }

    打开文件 Open :以只读方式打开文件,文件不存在也会打开失败

        参数:name,打开文件的路径,可以是绝对路径和相对路径

    package main
    
    import (
            "fmt";
             "os"
    )
    
    func main() {
    
        file, err := os.Open("./hello.txt")
        if err != nil {
            fmt.Println("Open error:", err)
            return
        }
        defer file.Close()
    
        _, err = file.WriteString("hello")
        if err != nil {
            fmt.Println("Write error:", err)
            return
        }
    
        fmt.Println("succes!")
    
    }

    结果

    Write error: write ./hello.txt: Access is denied.

    打开文件 OpenFile:以只读、只写、读写方式打开文件

        参数1:name,打开文件的路径,可以是绝对路径和相对路径

        参数2:打开文件权限,O_RDONLY、O_WRONLY、O_RDWR

        参数3:一般传6

    const (
    O_RDONLY int = syscall.O_RDONLY // 只读模式打开文件
    O_WRONLY int = syscall.O_WRONLY // 只写模式打开文件
    O_RDWR int = syscall.O_RDWR // 读写模式打开文件
    O_APPEND int = syscall.O_APPEND // 写操作时将数据附加到文件尾部
    O_CREATE int = syscall.O_CREAT // 如果不存在将创建一个新文件
    O_EXCL int = syscall.O_EXCL // 和O_CREATE配合使用,文件必须不存在
    O_SYNC int = syscall.O_SYNC // 打开文件用于同步I/O
    O_TRUNC int = syscall.O_TRUNC // 如果可能,打开时清空文件
    )

    package main
    
    import (
            "fmt";
             "os"
    )
    
    func main() {
    
        file, err := os.OpenFile("./hello.txt", os.O_RDWR, 6)
        if err != nil {
            fmt.Println("OpenFile error:", err)
            return
        }
        defer file.Close()
    
        _, err = file.WriteString("hello")
        if err != nil {
            fmt.Println("Write error:", err)
            return
        }
    
        fmt.Println("succes!")
    
    }

    结果

    succes!

    写文件

    按字符串写:WriteString(string str)

    _, err = file.WriteString("hello")

    回车换行 Windows为 Linux为

    按位置写:

        Seek():修改文件的读写指针位置

    func (f *File) Seek(offset int64, whence int) (ret int64, err error) {
        if err := f.checkValid("seek"); err != nil {
            return 0, err
        }
        r, e := f.seek(offset, whence)
        if e == nil && f.dirinfo != nil && r != 0 {
            e = syscall.EISDIR
        }
        if e != nil {
            return 0, f.wrapErr("seek", e)
        }
        return r, nil
    }

        参数1: 偏移量。正是向文件尾偏,负是向文件头偏

        参数2:偏移起始位置

                    io.SeekStart:文件起始的位置 0

                    io.SeekCurrent:文件当前位置 1

                    io.SeekEnd:文件结尾位置 2

        返回值:表示从文件起始位置到当前文件读写指针位置的偏移量

    按字节写:

        writeAt():在文件指定偏移位置,写入[]byte,通常搭配Seek()

        参数1:带写入的数据

        参数2:偏移量

        返回值:实际写出的字节数

    package main
    
    import (
        "fmt"
        "io"
        "os"
    )
    
    func main() {
    
        file, err := os.OpenFile("./hello.txt", os.O_RDWR, 6)
        if err != nil {
            fmt.Println("OpenFile error:", err)
            return
        }
        defer file.Close()
    
        _, err = file.WriteString("hello")
        if err != nil {
            fmt.Println("Write error:", err)
            return
        }
    
    
        off, _ := file.Seek(0, io.SeekStart)
        fmt.Println(off)  // 0
    
        off, _ = file.Seek(1, io.SeekCurrent)
        fmt.Println(off)  // 1
    
        off, _ = file.Seek(0, io.SeekEnd)
        fmt.Println(off)  // 5
    
        off, _ = file.Seek(-1, io.SeekEnd)
        fmt.Println(off) // 4
    
        off, _ = file.Seek(-2, io.SeekEnd)
        fmt.Println(off) // 3
    
        n, _ := file.WriteAt([]byte("111"), off)
        fmt.Println(n) //3
        
        fmt.Println("succes!")
    
    }

    文件 hello ---> hel111,偏移量3的地方开始写:

    读文件

    // Reader implements buffering for an io.Reader object.
    type Reader struct {
        buf          []byte
        rd           io.Reader // reader provided by the client
        r, w         int       // buf read and write positions
        err          error
        lastByte     int // last byte read for UnreadByte; -1 means invalid
        lastRuneSize int // size of last rune read for UnreadRune; -1 means invalid
    }
    func NewReaderSize(rd io.Reader, size int) *Reader {
        // Is it already a Reader?
        b, ok := rd.(*Reader)
        if ok && len(b.buf) >= size {
            return b
        }
        if size < minReadBufferSize {
            size = minReadBufferSize
        }
        r := new(Reader)
        r.reset(make([]byte, size), rd)
        return r
    }
    
    // NewReader returns a new Reader whose buffer has the default size.
    func NewReader(rd io.Reader) *Reader {
        return NewReaderSize(rd, defaultBufSize)
    }

    NewReader 返回的是结构体指针变量

    // ReadBytes reads until the first occurrence of delim in the input,
    // returning a slice containing the data up to and including the delimiter.
    // If ReadBytes encounters an error before finding a delimiter,
    // it returns the data read before the error and the error itself (often io.EOF).
    // ReadBytes returns err != nil if and only if the returned data does not end in
    // delim.
    // For simple uses, a Scanner may be more convenient.
    func (b *Reader) ReadBytes(delim byte) ([]byte, error) {
        // Use ReadSlice to look for array,
        // accumulating full buffers.
        var frag []byte
        var full [][]byte
        var err error
        n := 0
        for {
            var e error
            frag, e = b.ReadSlice(delim)
            if e == nil { // got final fragment
                break
            }
            if e != ErrBufferFull { // unexpected error
                err = e
                break
            }
    
            // Make a copy of the buffer.
            buf := make([]byte, len(frag))
            copy(buf, frag)
            full = append(full, buf)
            n += len(buf)
        }
    
        n += len(frag)
    
        // Allocate new buffer to hold the full pieces and the fragment.
        buf := make([]byte, n)
        n = 0
        // Copy full pieces and fragment in.
        for i := range full {
            n += copy(buf[n:], full[i])
        }
        copy(buf[n:], frag)
        return buf, err
    }

    按行读:

    package main
    
    import (
        "bufio"
        "fmt"
        "io"
        "os"
    )
    
    func main() {
    
        file, err := os.OpenFile("./hello.txt", os.O_RDWR, 6)
        if err != nil {
            fmt.Println("OpenFile error:", err)
            return
        }
        defer file.Close()
    
        fmt.Println("succes!")
    
        // 创建一个带缓冲区的reader
        reader := bufio.NewReader(file)
    
        for{
            buf, err := reader.ReadBytes('
    ') // 读一行
            if err != nil && err == io.EOF{
                fmt.Println("文件读取完毕")
                return
            }else if err != nil {
                fmt.Println("ReadBytes error:", err)
            }
            fmt.Print(string(buf))
        }
    
    }

    按字节读、写文件

    最常用

    read()

    write()

    大文件拷贝

    package main
    
    import (
        "fmt"
        "io"
        "os"
    )
    
    func main() {
    
        file_r, err := os.Open("E:/文档/xmind/C#.png")
        if err != nil {
            fmt.Println("Open err: ", err)
            return
        }
        defer file_r.Close()
        // 创建写文件
        file_w, err := os.Create("./C#.png")
        if err != nil {
            fmt.Println("Create err: ", err)
            return
        }
        defer file_w.Close()
    
        // 从读文件中读取数据,放到缓冲区中
        buf := make([]byte, 4096)
        // 循环,从读文件中读取数据,拷贝都写文件中
        for  {
            n, err := file_r.Read(buf)
            if err != nil && err == io.EOF {
                fmt.Printf("已经读完 n=%d
    ", n)
                return
            }
            file_w.Write(buf[: n]) // 读多少,写多少
        }
    }

    结果

    已经读完 n=0

    因此,我们也可以通过n=0来判断文件读取完毕

    目录操作

    打开目录,和打开目录是一样的

    目录中的内容叫目录项

    打开目录 OpenFile:以只读、只写、读写方式打开目录

        参数1:name,打开文件的路径,可以是绝对路径和相对路径

        参数2:打开文件权限,O_RDONLY、O_WRONLY、O_RDWR

        参数3:os.ModeDir

        返回值:返回一个可以读写目录的文件指针

    读目录

    func (f *File) Readdir(n int) ([]FileInfo, error) {
        if f == nil {
            return nil, ErrInvalid
        }
        return f.readdir(n)
    }

        参数:n,表示读取目录的成员个数。通常传-1,表示读取目录所有文件对象。

        返回值:FileInfo类型的切片。其内部保存了文件名。error中保存错误信息。

    // A FileInfo describes a file and is returned by Stat and Lstat.
    type FileInfo interface {
        Name() string       // base name of the file
        Size() int64        // length in bytes for regular files; system-dependent for others
        Mode() FileMode     // file mode bits
        ModTime() time.Time // modification time
        IsDir() bool        // abbreviation for Mode().IsDir()
        Sys() interface{}   // underlying data source (can return nil)
    }

    得到FileInfo类型切片后,可以range遍历切片元素,使用.Name()获取文件名。使用.Size()获取文件大小,使用.IsDir()判断文件是目录还是非目录文件

    如,我们可以提示用户提供一个目录位置,打开该目录,查看目录下的所有成员,并判别它们是文件还是目录。

    package main
    
    import (
        "fmt"
        "os"
    )
    
    func main() {
    
        // 获取用户输入的目录路径
        fmt.Println("请输入待查询的目录:")
        var path string
        path = "./"
        // 打开目录
        f, err := os.OpenFile(path, os.O_RDONLY, os.ModeDir)
        if err != nil {
            fmt.Println("Open dir error: ", err)
        }
        defer f.Close()
    
        // 读取目录项
        info, err := f.Readdir(-1)
    
        for _, fileInfo := range info{
            if fileInfo.IsDir(){
                fmt.Println(fileInfo.Name(), " 是一个目录")
            } else {
                fmt.Println(fileInfo.Name(), " 是一个文件c")
            }
        }
    
    }
  • 相关阅读:
    cs61b project1
    CS61b lab5
    leetcode DP
    Leetcode 还未解决的bug
    Git使用总结
    Mac TensorFlow Anaconda
    eclipse C++ ld: 1 duplicate symbol for architecture x86_64
    Leetcode Hashtable 1-5
    EC 601 PYTHONPATH
    EC 601 OpenCV Install
  • 原文地址:https://www.cnblogs.com/aidata/p/11729979.html
Copyright © 2020-2023  润新知