学习资料汇总
Go by Example
Go 初学者成长之路
系统推荐GO几本书
飞雪无情的博客
Go Web 编程 电子书
一、环境安装
1.推荐goland,不折腾
HELLO WORLD教程很多,安装完很容易就在命令行里go run了。接下来要找个编辑器,先用Vs code,可是插件太难安装了,翻墙也没成功,弃了。然后找到GoLand,不过免费版只能用1个月,网上找的激活码、激活服务器都失效了,先免费用着吧,以后在淘宝上买个码用用。
参考mac:Go安装和配置+GoLand安装和使用之完整教程
在项目hello文件夹下,我新建了一个src文件夹,这是go的默认用法。一般都将项目代码放在src文件夹下。代码中所有引用的第三方包路径,前缀都默认是"项目名/src/第三方包路径”。 如main.go中引用第三方包:
import “golang.org/x/net/websocket”
,那么该包必须位于“hello/src/”文件夹下,否则将找不到该依赖包而编译出错。
另外参考Jetbrains 家族利器之 Gogland 简明教程
二、golang fmt格式“占位符”
%d 十进制整数
%x, %o, %b 十六进制,八进制,二进制整数。
%f, %g, %e 浮点数: 3.141593 3.141592653589793 3.141593e+00
%t 布尔:true或false
%c 字符(rune) (Unicode码点)
%s 字符串
%q 带双引号的字符串"abc"或带单引号的字符'c'
%v 变量的自然形式(natural format)
%T 变量的类型
%% 字面上的百分号标志(无操作数)
比如fmt.Printf("%d,strig value:%s",value,string(value))
三、变量
参考快学 Go 语言》第 2 课 —— 变量基础
如果一个名字是在函数内部定义,那么它就只在函数内部有效。如果是在函数外部定义,那么将在当前包的所有文件中都可以访问。名字的开头字母的大小写决定了名字在包外的可见性。如果一个名字是大写字母开头的(译注:必须是在函数外部定义的包级名字;包级函数名本身也是包级名字),那么它将是导出的,也就是说可以被外部的包访问,例如fmt包的Printf函数就是导出的,可以在fmt包外部访问。包本身的名字一般总是用小写字母。
名字的长度没有逻辑限制,但是Go语言的风格是尽量使用短小的名字,对于局部变量尤其是这样;你会经常看到i之类的短名字,而不是冗长的theLoopIndex命名。通常来说,如果一个名字的作用域比较大,生命周期也比较长,那么用长的名字将会更有意义。
1.变量三种写法
var s int = 42
var s = 42//类型推导
s := 42//简短变量声明 自动类型推导 + 赋值
如果一个变量很重要,建议使用第一种显示声明类型的方式来定义,比如全局变量的定义就比较偏好第一种定义方式。如果要使用一个不那么重要的局部变量,就可以使用第三种。比如循环下标变量
for i:=0; i<10; i++ {
doSomething()
}
那第二种方式能不能用在上面的循环下标中呢,答案是不可以,你无法将 var 声明直接写进循环条件中的初始化语句中,而必须提前声明变量,像下面这样,这时就很明显不如上面的形式了
var i = 0
for ; i<10; i++ {
doSomething()
}
也可以在一个声明语句中同时声明一组变量,或用一组初始化表达式声明并初始化一组变量。
var i, j, k int // int, int, int
var b, f, s = true, 2.3, "four" // bool, float64, string
一组变量也可以通过调用一个函数,由函数返回的多个返回值初始化:var f, err = os.Open(name) // os.Open returns a file and an error
2.go没有静态变量
3.常量
Go 语言还提供了常量关键字 const,用于定义常量。常量可以是全局常量也可以是局部常量。
const globali int = 24
var var1 int = 7
fmt.Printf("%T->%v\n", var1, var1)
var2 := float32(var1)
var3 := int64(var1)
类型断言的本质,跟类型转换类似,都是类型之间进行转换,不同之处在于,类型断言实在接口之间进行,相当于Java中,对于一个对象,把一种接口的引用转换成另一种。
func test6() {
var i interface{} = "kk"
j := i.(int)
fmt.Printf("%T->%d\n", j, j)
}
把这个 i 转换成 int 类型,系统内部检测到这种不匹配,就会调用内置的panic()函数,抛出一个异常。改一下,把 i 的定义改为:var i interface{} = 99,就没问题了。输出为:int->99
5.数据类型
uint8
无符号 8 位整型 (0 到 255)
uint16
无符号 16 位整型 (0 到 65535)
uint32
无符号 32 位整型 (0 到 4294967295)
uint64
无符号 64 位整型 (0 到 18446744073709551615)
int8
有符号 8 位整型 (-128 到 127)
int16
有符号 16 位整型 (-32768 到 32767)
int32
有符号 32 位整型 (-2147483648 到 2147483647)
int64
有符号 64 位整型 (-9223372036854775808 到 9223372036854775807)
float32
IEEE-754 32位浮点型数
float64
IEEE-754 64位浮点型数
complex64
32 位实数和虚数
complex128
64 位实数和虚数
常量math.MaxFloat32表示float32能表示的最大数值,大约是 3.4e38;对应的math.MaxFloat64常量大约是1.8e308。它们分别能表示的最小值近似为1.4e-45和4.9e-324。
(1)int和uint,与CPU位数相关,可以参考Golang int 和 uint 天天用,那么问题来了,它多大?
(2)尽管Go语言提供了无符号数和运算,即使数值本身不可能出现负数我们还是倾向于使用有符号的int类型,就像数组的长度那样,虽然使用uint无符号类型似乎是一个更合理的选择。事实上,内置的len函数返回一个有符号的int,我们可以像下面例子那样处理逆序循环。
medals := []string{"gold", "silver", "bronze"}
for i := len(medals) - 1; i >= 0; i-- {
fmt.Println(medals[i]) // "bronze", "silver", "gold"
}
另一个选择对于上面的例子来说将是灾难性的。如果len函数返回一个无符号数,那么i也将是无符号的uint类型,然后条件 i >= 0 则永远为真。在三次迭代之后,也就是 i == 0 时,i--语句将不会产生-1,而是变成一个uint类型的最大值,然后medals[i]表达式将发生运行时panic异常,也就是试图访问一个slice范围以外的元素。
出于这个原因,无符号数往往只有在位运算或其它特殊的运算场景才会使用,就像bit集合、分析二进制文件格式或者是哈希和加密操作等。它们通常并不用于仅仅是表达非负数量的场合。
(3)参考能不能用 double 去取代 float?,浮点数建议直接使用float64。
(4)关于精度丢失,可以参考js 小数的精度损失
四、分支与循环
- Go 语言没有三元操作符
func sign(a int) int {
if a > 0 {
return 1
} else if a < 0 {
return -1
} else {
return 0
}
}
2.switch
func prize1(score int) string {
switch score / 10 {
case 0, 1, 2, 3, 4, 5:
return "差"
case 6, 7:
return "及格"
case 8:
return "良"
default:
return "优"
}
}
要注意,Go语言并不需要显式地在每一个case后写break,语言默认执行完case后的逻辑语句会自动退出。当然了,如果你想要相邻的几个case都执行同一逻辑的话,需要自己显式地写上一个fallthrough语句来覆盖这种默认行为。
3.Go 语言虽然没有提供 while 和 do while 语句,不过这两个语句都可以使用 for 循环的形式来模拟。
func main() {
for true {
fmt.Println("hello world!")
}
}
4.使用if合并判断
if err := r.ParseForm(); err != nil {
log.Print(err)
}
Go语言允许这样的一个简单的语句结果作为循环的变量声明出现在if语句的最前面,这一点对错误处理很有用处。我们还可以像下面这样写(当然看起来就长了一些):
err := r.ParseForm()
if err != nil {
log.Print(err)
}
用if和ParseForm结合可以让代码更加简单,并且可以限制err这个变量的作用域,这么做是很不错的。
网友评论