golang学习随便记1
Posted sjg20010414
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了golang学习随便记1相关的知识,希望对你有一定的参考价值。
准备工作
用vscode编写golang程序显然要麻烦一点,另外,在墙内也是多了一些麻烦,好在资源够多:
go get更换国内镜像源_goldVitaminC的博客-CSDN博客 用镜像才能顺利下载包(包括vscode插件)
The Go Programming Language (google.cn) 这个代替官网
以前是在linux下用,而且是先 gcc 编译低版本go,然后再用低版本go编译高版本编译器,windows下就直接下载二进制安装包 .msi 了,装完:
C:\\Program Files\\Go 这里是 go 自己的东西,包括标准库包,
用户主目录 %HOMEPATH% (如 c:\\users\\zime)下有go子目录,里面有 bin、src 和 pkg 子目录,当我们使用其他包(包括插件)时,下载到 pkg 子目录。我们的源代码放入src子目录(每个项目里面建立一个子目录)
和我以前用 go 不一样的地方是,现在推荐项目下有名称为 go.mod 的依赖跟踪文件,如果原来没有也简单 go mod init 模块路径名,这里 模块路径名 通常是项目在仓库的路径,类似 github.com/mymodule,这样可以确保 go的那些工具能下载这个包(如果我们的包并不需要给他人用,可以随便给个名称)
命令行参数
引入 "os" 包,os.Args 数组存放了命令行参数,项目 echo1
package main
import (
"fmt"
"os"
)
func main() {
var s, sep string
for i := 1; i < len(os.Args); i++ {
s += sep + os.Args[i]
sep = " "
}
fmt.Println(s)
}
os.Args[0] 为命令自己,os.Args[1]为第一个参数 ,如 go build 编译,./echo1 aaa bbb ccc 将输出 aaa bbb ccc
程序结构
常量
const boilingF = 212.0
const freezingF, boilingF = 32.0, 212.0
变量
var s string
var i, j, k int
var b, f, s = true, 2.3, "four"
var f, err = os.Open(name)
短变量声明,即用 := 在赋值的同时声明变量,用所赋值确定变量的类型,如
anim := gif.GIF { LoopCount: nframes }
freq := rand.Float64() * 3.0
t := 0.0
i, j := 0, 1
f, err := os.Open(name)
指针
和C指针基本类似,这里先略过
new函数
p := new(int)
fmt.Println(*p) // 0
*p = 2
fmt.Println(*p) // 2
new()是内置函数,不是关键字(可以有变量名为new,但它的作用下不能调用new()函数),相当于分配内存返回指针,因为 go中变量总是初始化的,所以上例中第一条打印语句输出0
变量生命周期
var global *int
func f() {
var x int
x = 1
global = &x
}
上例中,存在“变量逃逸”现象,即变量 x 尽管在函数 f 内部局部声明,但其地址赋值给了全局变量global,所以,编译器必然会将其分配在堆上。go可以保证变量逃逸下程序仍能正常运行,但过多的变量逃逸可能带来性能问题。
命名类型(类型别名)
这个差不多就是 typedef 的意思,例如定义两个类型分别表示摄氏温度类型和华氏温度类型:
type Celsius float64
type Fahrenheit float64
命名了这两个新类型之后,就可以用来声明常量和变量了
const (
AbsoluteZeroC Celsius = -273.15
FreezingC Celsius = 0
BoilingC Celsius = 100
)
func CToF(c Celsius) Fahrenheit { return Fahrenheit(c*9/5 + 32) }
func FToC(f Fahrenheit) Celsius { return Celsius((f - 32) * 5 / 9) }
值得注意的是,golang是比C++ “更强”的强类型语言,上面的例子中,尽管 Celsius 和 Fahrenheit 内部都是 64位浮点数,但不能直接把一个 Celsius 类型的变量值赋值给 Fahrenheit 类型的变量(反之亦然),也不能用一个Celsius类型变量减去(或加上)另一个Fahrenheit类型的变量,必须进行显式类型转换,上例中 Celsius(t) 和 Fahrenheit(t) 是类型转换,不是函数。
我们可以为新命名的类型“附加”它的字符串表达,即为类型附加 String() 方法,从而打印该变量时,会按指定的字符串表达输出——这个和php里面 echo $v; 时,输出$v的字符串表达一样(如果$v 是类实例,则 $v 的魔术方法 __toString() 自动被调用)
func (c Celsius) String() string { return fmt.Sprintf("%g°C", c) }
大致按以下意思理解:func + 拥有者实例c + String() + 返回类型 { ... return ... }
如果
c := FToC(212.0)
则直接 fmt.Println(c) 将输出 100°C,当然,我们仍然可以输出 c 的值
fmt.Println(c.String()) // "100°C"
fmt.Printf("%v\\n", c) // "100°C"
fmt.Printf("%s\\n", c) // "100°C"
fmt.Println(c) // "100°C"
fmt.Printf("%g\\n", c) // "100"
fmt.Printfln("float64(c)) // "100"
包和文件
golang每个文件开头都用 package 声明定义包的名称,当我们导入一个其他包时,那个包的成员(导出常量、导出变量、导出函数)可以用 packagename.CToF那样的方式引用。注意:这里有一个被王垠大神吐槽的点,就是哪些标识符是被导出的,哪些是外部不可见的,是按首字符大小写约定的(大写字母开头导出的,外部可见,小写字母开头是包内私有的)
包使用例子,创建 greetings 目录 和 hello目录,我们将在 hello项目引用greetings包。
<ch1>/ |-- greetings/ |-- hello/
在greetings目录用 go mod init example.com/greetings 创建依赖文件,然后创建 greetings.go 源文件如下:
package greetings
import "fmt"
func Hello(name string) string {
message := fmt.Sprintf("Hi, %v. Welcome!", name)
return message
}
注意,函数Hello首字母是大写的!
在 hello 目录同样用 go mod init example.com/hello 创建依赖文件,然后创建源代码文件 hello.go
package greetings
import "fmt"
func Hello(name string) string {
message := fmt.Sprintf("Hi, %v. Welcome!", name)
return message
}
这样直接 go run . 会出错,因为 go get 试图从仓库中去找 greetings 包,我们必须在 hello 项目的依赖文件告诉编译器,从本地文件系统找该包,所以,执行
go mod edit -replace example.com/greetings=../greetings
这时, go.mod 文件就多一句 replace 语句,再用 go mod tidy 同步一下模块依赖(就是找出我们的源码依赖哪些外部包,它们的版本是什么,然后在 go.mod 依赖文件进行记录),hello的go.mod文件如下
module example.com/hello
go 1.17
replace example.com/greetings => ../greetings
require example.com/greetings v0.0.0-00010101000000-000000000000
这时 go run . 就可以正常工作了
作用域
基本上和直觉一致,略过
以上是关于golang学习随便记1的主要内容,如果未能解决你的问题,请参考以下文章