分享
  1. 首页
  2. 文章

Golang 知识点

樊海鹏 · · 1041 次点击 · · 开始浏览
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

变量声明

var a
a=100
//或
var b = 100
//或
var c int = 100
// := 是声明并赋值,并且系统自动推断类型,不需要var关键字
d := 100
package main
import "fmt"
// 指针
func main() {
 // 切片的一种定义方式是 用 make
 // var x = make([]float64, 5) ,切片用make
 //另外一种是通过数组切片赋值,采用[low_index:high_index]的方式获取数值切片,其中切片元素包括low_index的元素,但是不包括high_index的元素。
 ar := new([3]int)// 指针
 ar1 := [3]int{0, 0, 0}
 var ar2 = [3]int{0, 0, 0}
 var ar3 [3]int
 var ar4 = [3]int{0: 1, 1: 2, 2: 3}
 fp(ar)
 fp(&ar1)
 fp(&ar2)
 fp(&ar3)
 fp(&ar4)
 fp1(ar)
 fp1(&ar1)
 fp1(&ar2)
 fp1(&ar3)
 fp1(&ar4)
}
func fp(a *[3]int) { print(*a) }
func fp1(a *[3]int) { print(a) }

与 Python不同

任何空值(nil)或者零值(0, 0.0, "")都不能作为布尔型来直接判断。

func main() {
 if 0 {
 fmt.Println("hello world")
 }
 if nil {
 fmt.Println("hello world")
 }
 if "" {
 fmt.Println("hello world")
 }
}

常用命令

go build: 编译出可执行文件
go install: go build + 把编译后的可执行文件放到GOPATH/bin目录下
go get: git clone + go install

何时使用指针

指针的一大用途就是可以将变量的指针作为实参传递给函数,从而在函数内部能够直接修改实参所指向的变量值。

Go的变量传递都是值传递。
package main
import (
 "fmt"
)
func change(x int) {
 x = 200
}
func main() {
 var x int = 100
 fmt.Println(x)
 change(x)
 fmt.Println(x)
}
上面的例子输出结果为
100
100
很显然,change函数改变的仅仅是内部变量x的值,而不会改变传递进去的实参。其实,也就是说Go的函数一般关心的是输出结果,而输入参数就相当于信使跑到函数门口大叫,你们这个参数是什么值,那个是什么值,然后就跑了。你函数根本就不能修改它的值。不过如果是传递的实参是指针变量,那么函数一看,小子这次你地址我都知道了,哪里跑。那么就是下面的例子:
package main
import (
 "fmt"
)
func change(x *int) {
 *x = 200
}
func main() {
 var x int = 100
 fmt.Println(x)
 change(&x)
 fmt.Println(x)
}
上面的例子中,change函数的虚参为整型指针变量,所以在main中调用的时候传递的是x的地址。然后在change里面使用*x=200修改了这个x的地址的值。所以x的值就变了。这个输出是:
100
200

一个函数何时该用指针类型做receiver对初学者而言一直是个头疼的问题。如果不知道该如何取舍,选择指针类型的receiver。但有些时候value receiver更加合适,比如对象是一些轻量级的不变的structs,使用value receiver会更加高效。下面是列举了一些常用的判断指导。

如果receiver是map、func或者chan,不要使用指针

如果receiver是slice并且该函数并不会修改此slice,不要使用指针

如果该函数会修改receiver,此时一定要用指针

如果receiver是struct并且包含互斥类型sync.Mutex,或者是类似的同步变量,receiver必须是指针,这样可以避免对象拷贝

如果receiver是较大的struct或者array,使用指针则更加高效。多大才算大?假设struct内所有成员都要作为函数变量传进去,如果觉得这时数据太多,就是struct太大

如果receiver是struct,array或者slice,并且其中某个element指向了某个可变量,则这个时候receiver选指针会使代码的意图更加明显

如果receiver使较小的struct或者array,并且其变量都是些不变量、常量,例如time.Time,value receiver更加适合,因为value receiver可以减少需要回收的垃圾量。

最后,如果不确定用哪个,使用指针类的receiver

常量

变量定义的类型推断方式 := 不能够用来定义常量

快速声明

Go还提供了一种同时定义多个变量或者常量的快捷方式。


import (
"fmt"
)
func main() {
 var (
 a int = 10
 b float64 = 32.45
 c bool = true
 )
 const (
 Pi float64 = 3.14
 True bool = true
 )
 fmt.Println(a, b, c)
 fmt.Println(Pi, True)
}

if 判断的()

package main

import (
"fmt"
)

func main() {
const Male = 'M'
const Female = 'F'

var dog_age = 10
var dog_sex = 'M'
if (dog_age == 10 && dog_sex == 'M') {
 fmt.Println("dog")
}

}


但是如果你使用Go提供的格式化工具来格式化这段代码的话,Go会智能判断你的括号是否必须有,否则的话,会帮你去掉的。你可以试试。
go fmt test_bracket.go
然后你会发现,咦?!果真被去掉了。
# for 循环

package main

import (
"fmt"
)

在Go里面没有提供while关键字,如果你怀念while的写法也可以这样:

func main() {
 var i int = 1
 for i <= 100 {
 fmt.Println(i)
 i++
 }
}
或许你会问,如果我要死循环呢?是不是for true?呵呵,不用了,直接这样。
for{
}

切片

我们发现arr1的长度变为11,因为元素个数现在为11个。另外我们发现arr1的容量也变了,变为原来的两倍。

这是因为Go在默认的情况下,如果追加的元素超过了容量大小,Go会自动地重新为切片分配容量,容量大小为原来的两倍。

总结一下,数组和切片的区别就在于[]里面是否有数字或者...!!!!!!!!!!!

因为数值长度是固定的,而切片是可变的。

函数预定义

命名返回值

Go的函数很有趣,你甚至可以为返回值预先定义一个名称,在函数结束的时候,直接一个return就可以返回所有的预定义返回值。例如上面的例子,我们将sum作为命名返回值。

package main
import (
"fmt"
)
func slice_sum(arr []int) (sum int) {
 sum = 0
 for _, elem := range arr {
 sum += elem
 }
 return
}
func main() {
 var arr1 = []int{1, 3, 2, 3, 2}
 var arr2 = []int{3, 2, 3, 1, 6, 4, 8, 9}
 fmt.Println(slice_sum(arr1))
 fmt.Println(slice_sum(arr2))
}

这里要注意的是,如果你定义了命名返回值,那么在函数内部你将不能再重复定义一个同样名称的变量。比如第一个例子中我们用sum := 0来定义和初始化变量sum,而在第二个例子中,我们只能用sum = 0初始化这个变量了。因为 := 表示的是定义并且初始化变量。

异常处理

panic & recover

当你周末走在林荫道上,听着小歌,哼着小曲,很是惬意。突然之间,从天而降瓢泼大雨,你顿时慌张(panic)起来,
没有带伞啊,淋着雨感冒就不好了。于是你四下张望,忽然发现自己离地铁站很近,那里有很多卖伞的,心中顿时又安定了下来(recover),于是你飞奔过去买了一把伞(defer )

Go语言提供了关键字defer来在函数运行结束的时候运行一段代码或调用一个清理函数。上面的例子中,虽然second()函数写在first()函数前面,但是由于使用了defer标注,所以它是在main函数执行结束的时候才调用的。


package main
import (
 "fmt"
)
func main() {
 //defer一定是在函数执行结束的时候运行的。不管是正常结束还是异常终止,相当于finally
 defer func() {
 //panic用来触发异常,而recover用来终止异常并且返回传递给panic的值。(注意recover并不能处理异常,而且recover只能在defer里面使用,否则无效。)
 msg := recover()
 fmt.Println(msg)
 }()
 fmt.Println("I am walking and singing...")
 panic("It starts to rain cats and dogs")
}

指针

定义

所谓指针其实你可以把它想像成一个箭头,这个箭头指向(存储)一个变量的地址。

因为这个箭头本身也需要变量来存储,所以也叫做指针变量。

new 的使用发现


package main
import (
 "fmt"
)
func set_value(x_ptr *int) {
//指针指向的地址内容设置为100
 *x_ptr = 100
}
func main() {
 //开辟一块内存,用于存贮指针地址,且此指针地址的变量名为x_ptr
 x_ptr := new(int)
 set_value(x_ptr)
 //指针变量指向的地址,因为本身就是指针变量,存贮的就是指向的地址
 fmt.Println(x_ptr)
 //指针变量本身的地址
 fmt.Println(&x_ptr)
 //打印指针变量指向的地址内容
 fmt.Println(*x_ptr)
}
0xc084000040
0xc084000038
100

有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:樊海鹏

查看原文:Golang 知识点

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

关注微信
1041 次点击
暂无回复
添加一条新回复 (您需要 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传

用户登录

没有账号?注册
(追記) (追記ここまで)

今日阅读排行

    加载中
(追記) (追記ここまで)

一周阅读排行

    加载中

关注我

  • 扫码关注领全套学习资料 关注微信公众号
  • 加入 QQ 群:
    • 192706294(已满)
    • 731990104(已满)
    • 798786647(已满)
    • 729884609(已满)
    • 977810755(已满)
    • 815126783(已满)
    • 812540095(已满)
    • 1006366459(已满)
    • 692541889

  • 关注微信公众号
  • 加入微信群:liuxiaoyan-s,备注入群
  • 也欢迎加入知识星球 Go粉丝们(免费)

给该专栏投稿 写篇新文章

每篇文章有总共有 5 次投稿机会

收入到我管理的专栏 新建专栏