您的位置:

Go语言面试题详解

一、基础语法

1、Go语言的基本类型有哪些?

Go语言的基础数据类型有:布尔型、数字型、字符串型、派生类型。布尔型的值只可以是常量 true 或者 false。数字类型包含整型和浮点型。其中整型包括 int8、int16、int32、int64、uint8、uint16、uint32、uint64 和 uintptr,浮点型包括 float32 和 float64。Go 语言中不允许不同类型之间的混合使用,但支持类型的转换。

var (
    isBool bool = true
    name string = "go language"
    age int = 20
    weight float64 = 60.1
)

2、列举Go语言的控制语句

Go 语言支持普通的控制流程语句:if、switch、for 和循环控制语句:break、continue 和 goto。if 语句将根据条件表达式的结果,决定执行哪条语句块。switch 语句用于编写一系列的 if-else 语句。for 语句是 Go 语言中唯一的循环语句,它支持 for-range 格式,可以遍历字符串、数组、切片、map、管道等。break 跳出当前循环,continue 语句放弃当前循环中的剩余语句。goto 语句将程序转到标记的语句处。

for i := 0; i < 10; i++ {
    if i == 5 {
        continue
    }
    fmt.Println(i)
    if i == 7 {
        break
    }
}

3、Go语言中的指针有什么特点?

Go 语言中的指针不能做指针运算,但是可以通过使用 unsafe 包实现指针运算;使用指针时,需要注意内存泄漏和空指针问题;可以使用 new() 和 & 两种方式来创建指针类型变量,new(T) 返回一个指向类型 T 的零值的指针,& 取某个变量的地址。

// 指针类型的定义和初始化
var p *int
p = &a

// new() 函数用法
p := new(int)
*p = 100

二、并发编程

1、什么是并发编程?

并发编程是指多个执行路径同时执行,但不一定是同时完成。在 Go 语言中,可以使用 goroutine 实现并发编程,goroutine 是 Go 语言中的轻量级线程,它可以在很小的栈空间上进行并发运算。

2、如何创建 goroutine?

使用 go 关键字即可创建一个 goroutine,即 go f(),其中 f() 是一个函数。

func main() {
    go show()
}
func show() {
    fmt.Println("Hello, Go")
}

3、如何进行同步操作?

Go 语言提供了 sync 包,通过它可以实现同步操作。sync.WaitGroup 可以用于等待一组 goroutine 的结束。类似于 Java 的 CountDownLatch 或者 C# 的 ManualResetEvent。

func main() {
    var wg sync.WaitGroup
    for i := 0; i < 10; i++ {
        wg.Add(1)
        go func(index int) {
            fmt.Println("goroutine", index)
            wg.Done()
        }(i)
    }
    wg.Wait()
    fmt.Println("all goroutine completed.")
}

三、网络编程

1、Go语言中如何进行TCP/UDP编程?

Go 语言提供了 net 包可用于 TCP/UDP 编程。使用 net.Listen() 函数监听端口,使用 net.Dial() 函数与服务器建立连接。基本流程:服务端创建监听,接受客户端连接请求,分配 goroutine 处理连接,客户端通过 Dial() 连接服务端。

2、如何创建一个TCP服务端?

func main() {
    ln, err := net.Listen("tcp", "127.0.0.1:8005")
    if err != nil {
        fmt.Println("listen err:", err)
        return
    }
    defer ln.Close()
    fmt.Println("server started, listening on", ln.Addr())
    for {
        conn, err := ln.Accept()
        if err != nil {
            fmt.Println("accept err:", err)
            continue
        }
        go handleConn(conn)
    }
}
func handleConn(conn net.Conn) {
    defer conn.Close()
    fmt.Println("accepted client", conn.RemoteAddr())
    var buf [512]byte
    for {
        n, err := conn.Read(buf[:])
        if err != nil {
            fmt.Println("read err:", err)
            return
        }
        str := string(buf[:n])
        fmt.Println("recv:", str)
        _, err = conn.Write([]byte("hello, client"))
        if err != nil {
            fmt.Println("write err:", err)
            return
        }
    }
}

3、如何创建一个UDP客户端?

func main() {
    addr, err := net.ResolveUDPAddr("udp", "127.0.0.1:8007")
    if err != nil {
        fmt.Println("resolve err:", err)
        return
    }
    conn, err := net.DialUDP("udp", nil, addr)
    if err != nil {
        fmt.Println("dial err:", err)
        return
    }
    defer conn.Close()

    _, err = conn.Write([]byte("hello, server"))
    if err != nil {
        fmt.Println("write err:", err)
        return
    }
    var buf [512]byte
    n, err := conn.Read(buf[:])
    if err != nil {
        fmt.Println("read err:", err)
        return
    }
    str := string(buf[:n])
    fmt.Println("recv:", str)
}

四、Web编程

1、如何创建一个HTTP服务端?

使用 net/http 包中的 http.ListenAndServe() 函数可以创建一个 HTTP 服务端。在定义处理函数时,可以使用 http.HandleFunc() 函数定义多个路由,通过启动 HTTP 服务,可以通过访问服务器地址和端口号访问服务。

func main() {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "Hello, Go!")
    })
    fmt.Println("server started at 127.0.0.1:8000")
    err := http.ListenAndServe("127.0.0.1:8000", nil)
    if err != nil {
        fmt.Println("listen err:", err)
    }
}

2、如何通过 HTTP 服务端实现文件下载和上传?

通过实现合适的路由和处理函数,可以方便地实现文件下载和上传功能。

文件下载示例:

func main() {
    http.HandleFunc("/download", func(w http.ResponseWriter, r *http.Request) {
        fileName := "./test.txt"
        f, err := os.Open(fileName)
        if err != nil {
            fmt.Println("open file err:", err)
            return
        }
        defer f.Close()
        buf := make([]byte, 1024)
        for {
            n, err := f.Read(buf[:])
            if err != nil {
                if err == io.EOF {
                    break
                }
                fmt.Println("read file err:", err)
                return
            }
            w.Write(buf[:n])
        }
    })
    fmt.Println("server started at 127.0.0.1:8000")
    err := http.ListenAndServe("127.0.0.1:8000", nil)
    if err != nil {
        fmt.Println("listen err:", err)
    }
}

文件上传示例:

func main() {
    http.HandleFunc("/upload", func(w http.ResponseWriter, r *http.Request) {
        if r.Method == "POST" {
            // 接收文件,最大2M
            file, header, err := r.FormFile("uploadfile")
            if err != nil {
                fmt.Println("get upload file err:", err)
                return
            }
            fileName := "./" + header.Filename
            defer file.Close()
            f, err := os.OpenFile(fileName, os.O_WRONLY|os.O_CREATE, 0666)
            if err != nil {
                fmt.Println("create file err:", err)
                return
            }
            defer f.Close()
            buf := make([]byte, 1024*2)
            for {
                n, err := file.Read(buf[:])
                if err != nil {
                    if err == io.EOF {
                        break
                    }
                    fmt.Println("read file err:", err)
                    return
                }
                f.Write(buf[:n])
            }
            fmt.Fprintln(w, "upload success")
        } else {
            fmt.Fprintln(w, "not support "+r.Method)
        }
    })
    fmt.Println("server started at 127.0.0.1:8000")
    err := http.ListenAndServe("127.0.0.1:8000", nil)
    if err != nil {
        fmt.Println("listen err:", err)
    }
}

五、数据库操作

1、Go语言中如何操作MySQL数据库?

Go 语言中操作 MySQL 数据库可以使用第三方库 go-sql-driver/mysql。通过这个库可以操作数据库的增、删、改、查等操作。使用 database/sql 包可以操作多种不同的数据库,是一个抽象的数据库驱动层。

2、如何创建一个MySQL连接?

func main() {
    dsn := "root:password@tcp(127.0.0.1:3306)/test"
    db, err := sql.Open("mysql", dsn)
    if err != nil {
        fmt.Println("open mysql error:", err)
        return
    }
    db.SetMaxOpenConns(10)
    db.SetMaxIdleConns(5)
    defer db.Close()
    fmt.Println("mysql connected.")
}

3、如何执行一个MySQL查询操作?

通过查询语句和参数传入查询语句执行查询操作即可。使用 Rows.Scan() 函数获取查询结果,在查询执行完毕后关闭 rows。

func main() {
    dsn := "root:password@tcp(127.0.0.1:3306)/test"
    db, err := sql.Open("mysql", dsn)
    if err != nil {
        fmt.Println("open mysql error:", err)
        return
    }
    db.SetMaxOpenConns(10)
    db.SetMaxIdleConns(5)
    defer db.Close()

    rows, err := db.Query("SELECT id,name,age FROM user WHERE id=?", 1)
    if err != nil {
        fmt.Println("query error:", err)
        return
    }
    defer rows.Close()

    for rows.Next() {
        var id int
        var name string
        var age int
        err := rows.Scan(&id, &name, &age)
        if err != nil {
            fmt.Println("scan error:", err)
            return
        }
        fmt.Printf("id=%d,name=%s,age=%d\n", id, name, age)
    }
}

通过本文的详细讲解,你已经了解了Go语言的一些面试题,并找到了相关的代码实现。希望这篇文章对你的面试有所帮助!