赞
踩
转Golang的第一天记录工作
本人是从Java语音转到Golang的,无奈形式所迫。但也是契机吧!
由于,之前大都使用的是JET家的IDE,故GoLang也使用的是。
具体安装过程,完全参考下面文章: 【Go】Goland下载与安装教程(详细)
还是有些许问题需要记录一下。
在 Go 语言中,GOPATH
是一个环境变量,用于指定 Go 语言的工作空间(workspace)路径。它定义了 Go 编译器在查找包和存储编译结果时应该使用的目录结构。
GOPATH
的主要作用有以下几个方面:
包的安装位置:GOPATH
指定了包的安装路径。当你使用 go get
命令下载和安装新的包时,默认会将这些包安装到 GOPATH
指定的路径下的 src
、bin
和 pkg
目录中。src
目录用于存放源码,pkg
目录用于存放编译后的包文件,bin
目录用于存放可执行文件。
包的查找路径:在编译和运行 Go 代码时,编译器和运行时会根据 GOPATH
中的路径来查找导入的包。当你在代码中使用 import
导入其他包时,Go 编译器会根据 GOPATH
中的路径去寻找对应的包。
工作空间的管理:GOPATH
可以看作是 Go 语言的工作空间,它允许你将你的项目和依赖包组织在一个统一的目录结构下。你可以在 GOPATH
下创建不同的目录来组织不同的项目,每个项目都可以有自己的源码和依赖包。
需要注意的是,从 Go 1.11 版本开始,Go 引入了 Go 模块(Go Modules),它改变了包的下载和依赖管理方式,并不再强制要求使用 GOPATH
。如果你使用 Go 模块来管理你的项目,你可以不再依赖 GOPATH
环境变量,而是将你的项目放在任何你喜欢的位置,并使用 go mod
命令来初始化和管理模块。
总结起来,GOPATH
环境变量定义了 Go 语言的工作空间路径,用于包的安装、查找和管理。但随着 Go 模块的引入,不再强制依赖 GOPATH
,而是提供了更灵活的包管理方式。
在 Go 语言中,package main
是一个特殊的包声明,其作用是指示编译器将该文件视为可执行程序的入口点。
当你编写一个可执行的 Go 程序时,你需要在其中的一个文件中使用 package main
来声明 main
包。这个包是 Go 程序的入口点,它包含了程序的入口函数 main()
。
具体来说,package main
的作用和定位如下:
入口函数的位置:在 Go 程序中,main
包中的 main()
函数是程序的入口函数,它是程序执行的起点。当你运行一个 Go 可执行程序时,操作系统会首先调用 main
包中的 main()
函数来启动程序的执行。
可执行程序的标识:使用 package main
声明的文件是一个可执行程序的标识。当你使用 go build
命令构建可执行文件时,Go 编译器会查找 package main
声明的文件,并将其作为程序的入口文件进行编译。
需要注意的是,一个包只能有一个 package main
声明,且这个声明只能用于可执行程序的入口文件。其他的库文件应该使用不同的包名称,并且不包含 package main
声明。
总结起来,package main
声明标识了一个 Go 可执行程序的入口点,并指示编译器将其作为程序的入口文件进行编译和执行。在 main
包中,main()
函数作为程序的入口函数,在程序启动时被调用。
结构体类似Java语言中的class,可以在结构体中定义多个字段,为结构体实现方法,实例化等。
代码如下(定义结构体Student 添加name、age字段并实现hello()方法):
package main import "fmt" type Student struct { name string age int } func (stu *Student) hello(person string) string { return fmt.Sprintf("hello %s, I am %s", person, stu.name) } func main() { stu := &Student{ name: "Tom", } msg := stu.hello("Jack") fmt.Printf(msg) stu2 := new(Student) stu2.name = "xiaoming" fmt.Printf(stu2.hello("Alice")) }
接口定义了一组方法的集合,接口不能被实例化,一个类型可以实现多个接口
代码如下(定义一个接口Person和对应的方法getName()和getAge):
package main import "fmt" type Person interface { getName() string } type Student struct { name string age int } func (stu *Student) getName() string { return stu.name } type Worker struct { name string gender string } func (w *Worker) getName() string { return w.name } func main() { var p Person = &Student{ name: "Tom", age: 19, } fmt.Println(p.getName()) }
Go语言中,并不需要显示地声明实现了哪一个接口,只需要直接实现该接口对应的方法即可。
当一个类型实现了某个接口中定义的所有方法时,我们说该类型满足(或实现)了该接口。
若没有全部实现,实例转换为接口则会报错。
var _ Person = (*Student)(nil)
var _ Person = (*Worker)(nil)
可以使用上面的方式进行验证。
空接口 :如果定义了一个没有任何方法的空接口,那么这个接口可以表示任意类型。例如
func main() {
m := make(map[string]interface{})
m["name"] = "Tom"
m["age"] = 18
m["scores"] = [3]int{98, 99, 85}
fmt.Println(m) // map[age:18 name:Tom scores:[98 99 85]]
}
在 Go 语言中,init()
函数是一种特殊的函数,它用于在程序启动时执行一些初始化操作。每个包可以包含一个或多个 init()
函数,它们会按照它们在源代码中的顺序自动执行。
init()
函数的执行时机如下:
当程序启动时,Go 运行时会自动调用每个包中的 init()
函数。这些 init()
函数按照它们在源代码中的顺序依次执行。
如果一个包被导入多次,它的 init()
函数只会执行一次。这意味着无论导入该包的代码有多少个,该包中的 init()
函数只会在第一次导入时执行。
init()
函数没有参数和返回值。
init()
函数通常用于执行一些初始化操作,例如初始化全局变量、注册模块、加载配置文件等。它们在程序启动阶段提供了一个执行额外逻辑的机会,以确保程序在运行之前处于正确的状态。
需要注意的是,init()
函数不能被显式地调用或引用,它们由 Go 运行时自动管理和执行。
总结起来,init()
函数是在程序启动时自动执行的特殊函数,用于执行包的初始化操作。它们按照它们在源代码中的顺序依次执行,并在包被导入时只执行一次。
在 Go 语言中,defer
用于延迟执行一个函数调用,即将该函数的执行推迟到当前函数返回之前。defer
关键字通常用于资源管理、错误处理和清理操作等场景。
defer
块的定位和作用如下:
定位:defer
块是通过在函数中的语句前添加 defer
关键字来定义的。它可以出现在函数内的任何位置,通常放在需要进行延迟处理的语句之前。
作用:defer
语句的作用是将其后面的函数调用推迟到包含 defer
语句的函数返回之前执行。无论函数是正常返回还是发生了异常,defer
语句都会被执行。
defer
的一些常见用途和好处包括:
defer
经常用于确保在函数返回之前释放已分配的资源,如关闭文件句柄、释放锁等。通过将相关的释放操作放在 defer
语句中,可以避免资源泄漏和忘记释放的问题。func readFile(filename string) {
file, err := os.Open(filename)
if err != nil {
// 错误处理
return
}
defer file.Close() // 在函数返回之前关闭文件
// 读取文件内容并进行处理
// ...
}
defer
可以用于在函数退出时记录日志,以提供函数的执行、错误和性能信息。func handleRequest(req *http.Request) {
start := time.Now()
defer func() {
log.Printf("Request processed in %s", time.Since(start))
}()
// 处理请求的逻辑
// ...
}
defer
语句可以用于捕获和处理函数执行过程中发生的错误,并在函数返回之前执行特定的错误处理逻辑。func processRequest(req *http.Request) {
resp, err := makeHTTPRequest(req)
if err != nil {
// 错误处理
return
}
defer resp.Body.Close() // 在函数返回之前关闭响应体
// 处理响应内容
// ...
}
请注意,defer
语句的执行顺序是后进先出的,即最后一个 defer
语句会最先执行,而第一个 defer
语句会最后执行。
defer
的使用可以帮助提高代码的可读性和可维护性,尤其是在需要进行资源管理和错误处理的情况下。
Go语言提供了两种方式支持协程的并发----sync、channel
import ( "fmt" "sync" "time" ) var wg sync.WaitGroup func download(url string) { fmt.Println("start to download", url) time.Sleep(time.Second) // 模拟耗时操作 wg.Done() } func main() { for i := 0; i < 3; i++ { wg.Add(1) go download("a.com/" + string(i+'0')) } wg.Wait() fmt.Println("Done!") }
使用channel信道,可以在协程之间传递消息。阻塞等待并发协程返回消息。
var ch = make(chan string, 10) // 创建大小为 10 的缓冲信道 func download(url string) { fmt.Println("start to download", url) time.Sleep(time.Second) ch <- url // 将 url 发送给信道 } func main() { for i := 0; i < 3; i++ { go download("a.com/" + string(i+'0')) } for i := 0; i < 3; i++ { msg := <-ch // 等待信道返回消息。 fmt.Println("finish", msg) } fmt.Println("Done!") }
NewCodecFunc
作为一个函数类型的作用是定义了一个函数签名,用于创建 Codec
对象或执行其他与 Codec
相关的操作。它可以作为函数参数、函数返回值或者结构体字段来使用。
作为函数参数:
func ProcessData(fn NewCodecFunc) {
conn := openConnection()
codec := fn(conn)
// 使用 codec 对象进行数据处理
// ...
}
func main() {
ProcessData(func(closer io.ReadWriteCloser) Codec {
// 在这里创建并返回一个符合 Codec 类型的对象
// ...
})
}
作为函数返回值:
func CreateCodecFactory() NewCodecFunc {
return func(closer io.ReadWriteCloser) Codec {
// 在这里创建并返回一个符合 Codec 类型的对象
// ...
}
}
func main() {
codecFactory := CreateCodecFactory()
conn := openConnection()
codec := codecFactory(conn)
// 使用 codec 对象进行数据处理
// ...
}
作为结构体字段:
type Server struct { codecFactory NewCodecFunc // ... } func (s *Server) Start() { conn := acceptConnection() codec := s.codecFactory(conn) // 使用 codec 对象进行数据处理 // ... } func main() { server := &Server{ codecFactory: func(closer io.ReadWriteCloser) Codec { // 在这里创建并返回一个符合 Codec 类型的对象 // ... }, } server.Start() }
通过使用 NewCodecFunc
函数类型,可以将具体的创建 Codec
对象的实现逻辑封装在函数中,并且可以在不同的上下文中传递和使用该函数。这种灵活性使得可以根据需要动态地创建不同类型的 Codec
对象,从而实现对数据的编解码或其他相关操作。
需要根据具体的需求和上下文,实现 NewCodecFunc
函数类型的函数,以创建或操作与 Codec
相关的对象。
该处使用的url网络请求的数据。
零零碎碎的记录了一些Go语言的知识点!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。