一、基础语法
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语言的一些面试题,并找到了相关的代码实现。希望这篇文章对你的面试有所帮助!