初识Go语言
本篇内容的基础学习参考自菜鸟教程Go语言
一、了解Go语言的结构
上图是一个简单的结构
go的代码按每行结束,可以不加分号结束。但是在单行内写多行就要自己添加分号分割内容
(一)包名
package main
首先,一个Go文件需要一个包名,包名可以为main,表示一个可独立执行的程序。可以运行的Go程序都包含一个名为main的包。
没有声明包名将会报错~
(二)导入包
import "fmt"
or
import (
"fmt"
)
然后,如果需要使用一些内置函数,则需要导入相应的包,导入的方式为
import “包名”
Go语言导入的包必须要被使用,导入包却没有使用将报错~
(三)main函数
func main(){
fmt.Println("")
}
学习过C或Java的朋友应该都知道main函数,Go的main函数也类似。Go程序开始时就会执行main函数,没有main函数将报错,如下图~
二、变量和常量
(一)Go的变量声明
var [paramName] [paramType]
//未声明的变量自动赋予缺省值
var myVal int
var myVal2 int = 1
go还有一种快捷的声明方式
[paramName] := [paramVal]
myVal := "第一个Go变量"
这个声明方式等效于
var myVal string
myVal = "第一个Go变量"
太好了,编辑器自动判断了myVal的值!
但是,不能在这种声明方式前声明。不然,就会报错~
一个一个值赋值麻烦?go可以多个值一起赋!
var _a string
var _b , _c int
_a , _b , _c = "初值" , 2 , 1
or
a , b , c := 1 , 2 , "初值"
(二)变量的交换
go的变量交换有一种极简的写法
a , b = b , a
(三)常量的声明
const [paramName] [paramType]
const MYCONST int = 1
const MYCONST2 = "第二个go常量"
const (
MYCONST3 = 0
MYCONST4 = 1
)
Go还有一个特别有意思的东西,叫iota
iota在const内出现的第一次会被重置为0,在新的一行被使用时会自加1。
那么在这里定义
const (
A = iota
B
C = "No iota"
D
E = iota
)
fmt.Println(A,B,C,D,E)
试问ABCDE分别是什么值?
这代表即使没有使用iota,也会加1。
那么,如果将多行常量声明在一行呢?
const (
A = iota;B;C = "No iota"
D
E = iota
)
fmt.Println(A,B,C,D,E)
结果没变~所以正确来说iota并不是一行加1,而是遇到下一个常量加1!
三、Go函数
终于到函数了!先奉上go的函数结构
(一)函数结构
func [funcName] ([paramsName] [paramsType]) [returnParamsType]{
…
}
func Add(a , b int) int {
return a + b
}
func Swap(a , b int) (int , int) {
return b , a
}
从上面的例子可以注意到,go函数可以返回 多 个 值!(落泪)
为什么a没有指定类型?那如果上面的例子给a赋一个string的值会怎么样嘞?
func Swap(a , b int) (int , int) {
a = "123"
return b , a
}
试一下只给a指定类型
func Swap(a int, b) (int , int) {
return b , a
}
(如果传入值的类型一样,那么可以只在后面的参数声明类型)
(二)参数传递方式
go参数传递有常规的 值传递 和 引用传递
-
值传递
func main(){ a , b := 1 , 2 Swap(a , b) fmt.Println(a , b) } func Swap(a , b int){ a , b = b , a }
可以看到main函数中a、b的值并没有改变
-
引用传递
func main(){ a , b := 1 , 2 Swap(&a , &b) fmt.Println(a , b) } func Swap(a , b *int){ *a , *b = *b , *a }
a、b值交换
&a表示a的指针,也可以理解为a的地址,计算机内a变量的门牌号,类型是[*a的类型],这里是*int。引用传递的swap函数相当于交换了a、b的地址,a住在了b的家,b去了a的家里面。
(三)函数变量作为参数
在go中,函数也能作为变量。类型是 func([paramsType])([returnParamsType])
func(int,int) (int,int)
下面的例子是callBack函数作为变量,playerAction函数调用作为变量的callBack函数
func main(){
playAction(1,callBack)
}
func playAction(a int,f func(int)){
f(a)
}
func callBack(x int){
fmt.Printf("回调:%d",x)
}
(四)闭包
闭包的另一个说法就是函数返回值是匿名函数。上结构
func [funcName] () func() [returnFuncReturnType]{
return func() [returnType]{
return …
}
}
func GetScore() func() int{
i := 0
return func() int{
i++
return i
}
}
func main(){
score1 := GetScore()
fmt.Println(score1())
fmt.Println(score1())
fmt.Println(score1())
}
运行结果:
可以看出第一次score1赋值时并没有调用函数。如果我新加入一个score2呢?
func GetScore() func() int{
i := 0
return func() int{
i++
return i
}
}
func main(){
score1 := GetScore()
fmt.Println(score1())
fmt.Println(score1())
fmt.Println(score1())
score2 := GetScore()
fmt.Println(score2())
fmt.Println(score2())
fmt.Println(score2())
}
运行结果:
看来,每获得一个新的闭包,闭包中的i不会互相影响。
但是,把score2的赋值换一下,换成了
score2 := score1
运行一下,发现i继续自增。score2住进了score1的家,所以score1和score2的i都是一样的。
(五)结构体方法
结构体struct可以包含很多变量,结构体方法可以省略一些繁杂的过程。
上结构:
func ([structName] [structType]) [funcName] () [returnParamsType]{
}
如果使用普通的方法对结构体进行操作,比较复杂:
type Circle struct{
radius float64
}
func main(){
var c1 Circle
c1.radius = 10
fmt.Println(GetArea(c1.radius))
}
func GetArea(r float64) float64{
return r * r
}
这种方法每次需要自己传入参数。结构体方法是不需要的:
type Circle struct{
radius float64
}
func main(){
var c1 Circle
c1.radius = 10
fmt.Println(c1.GetArea())
}
//结构体方法
func (c Circle)GetArea() float64{
return c.radius * c.radius
}
但需要注意的是,结构体方法只能接受一个值或指针。若有多个参数嘛……
func (c Circle,int i)GetArea() float64{
return c.radius * c.radius
}
三、函数调用
(一)调用同一包(文件夹)下的函数
Go语言的同一包(文件夹)下的Go程序需要同一包名,否则报错
first.go:
package main
import (
"fmt"
)
func main(){
fmt.Println("Hello World!");
fmt.Println(Add(1,2));
}
alg.go:
package alg
func Add(a ,b int) int {
return a + b
}
这里将alg.go的包名改为main,再在cmd命令行中build一下,成功。
(二)调用不同包函数
遇到报错cannot find module for path的话,先尝试cmd输入
go env -w GO111MODULE=off
C:\Go_WorkSpace\firstGo\first.go:
package main
import (
"fmt"
"./Alg"
)
func main(){
fmt.Println("Hello World!");
fmt.Println(myClass.Add(1,2));
}
在使用到其他包函数或变量的程序中导入对应包(文件夹名),调用时在函数前加上包名
C:\Go_WorkSpace\firstGo\Alg\alg.go:
package myClass
func Add(a ,b int) int {
return a + b
}
好了,下次再学