Go 语言入门指南:基础语法(1) | 青训营

86 阅读5分钟

1.神奇的开始

我们就以传统的hello,world开始!

package main

import "fmt"

func main() {
    fmt.Println("Hello, world")
}

下面就开始运行这段代码,常用的有go build 和go run命令

go run helloworld.go

这个命令就会输出:

Hello, world

如果你想让你的程序编译后在未来进行使用,那么 go build就派上用场了。

go build helloworld.go

此时会生成一个helloworld.exe文件,你可以随时的运行他,结果也是相同。

2.基础类型

2.1 内置类型

go语言常用的有布尔型,字符串,字符还有庞大的数值类型。 布尔型:

var flag bool //默认为false
var f = true

整形: 在32位CPU上,int等同于int32;在64位CPU上,int等同于int64

整形名称数值范围
int8-128~127
int16-32768~32767
int32-2147483648~2147483647
int64-9223372036854775808~9223372036854775807
uint80~255
uint160~65536
uint320~4294967295
uint640~18446744073709551615

浮点型:float32,float64

字符串: 与整型、浮点型一样,字符串可以使用==和!=进行比较,使用>、>=、<或者<=进行比较排序,使用+将字符串合并成一个新的字符串。 字符串是不可变的,编程中这表示一个一旦被设置就不能改变的值,即当我们修改了一个字符串的变量的值后,字符串其实已经不是原来的字符串了。

Go语言的设计从清晰表达意图和可读性出发,不允许变量之间进行自动类型转换,当变量之间类型不一致时,就必须进行显式类型转换。即使是整型或者浮点型,只要类型的大小不同,也必须转换成相同的类型。

2.2 var与:=

var x int =10
var x =10 //如果=右侧是变量的预期类型,那么可以省略=左侧的类型
var x ,y int =10,20 //当有多个类型相同的变量需要声明
var x ,y =1,"hello" //多个类型不同的变量
//还可以一次性声明多个变量
var(
    x int 
    y =20
    z int =30
    d,e =40,"hello"
   
)
//短声明格式:=
var x=10
x:=10
x,y:=10,"hello"
//:=运算符还有使用var关键字无法完成的功能:它允许对已经赋值的变量再次赋值,只要:=左边有任意一个新变量即可:
x:=10
x,y:=20,30

短声明格式只能用来声明在函数内部的局部变量,如果在包级别声明变量,只能使用var关键字,:=是不合法的。
通常,在函数内部选择使用:=的短声明格式;在函数外,包级别使用var的多变量声明格式。

2.2常量

const x int64 = 10
const(
    id ="id"
    name = "name"
)
const z =20*10

Go中只有常量具有不可变性,变量是不能不可变的。

const x =10
//由于x是无类型的常量,因此以下的赋值操作都是合法的
var y int =x
var z float64=x
const c int =10 //此时只能使用int类型的值对其进行赋值。

Go要求每个声明的局部变量必须被读取(read),声明局部变量而不读取其值会导致编译时错误。

2.3常量与变量的命名

与大部分编程语言一样,Go语言要求标识符名称以字母或者下划线开头,名称中可以包含任意数字、下划线或者字母,而且在Go语言中,字母和数字有更广泛的定义,任何Unicode字符的字母或者字符都是允许的。

在Go语言中当变量名包含多个单词时,约定使用驼峰命名法(比如indexCounter或者numberTries),而不是蛇形命名法(比如index_counter或者number_tries)。

在众多高级编程语言中,常量一直使用大写字母,单词间使用下划线分隔(比如INDEX_COUNTER或NUMBER_TRIES)。但是Go没有遵守这个模式,因为Go使用包级别声明名称中首字母的大小来确定这个变量外部访问的可见性。

3.复合类型

3.1数组

var x [3]int //定义一个包含3个整形元素的数组,都为0
var x = [3]int{10,20,30} //指定值
var x =12[int]{1,5:4,10:12} //此时的数组为:[1,0,0,0,0,4,0,0,0,0,12,0]
var x=[...]int{10,20,30}//也可以不定义具体的长度

可以使用==和!=比较数组

var a =[...]int{1,2,3}
var b =[3]int{1,2,3}
fmt.Println(x==y) //true

就像其他语言一样,在Go中读取和写入数组一般使用中括号语法:

x[0]=10

数组在Go中很少被显式地使用。这是因为它们有一个特殊的限制:Go认为数组的长度属于其类型的一部分。这就导致定义为[3]int的数组类型不同于定义为[4]int的数组类型,也意味着不能使用变量去指定数组的长度,因为类型必须在编译时而不是在运行时解析。

3.2切片

使用切片和数组非常相似

var x =[]int{10,20,30}//在声明切片是没有指定他的长度
//其他的读写和数组操作一致
//不同之处在于可以定义一个不带字面量的切片
var x[]int //此时值为nil,代表某些类型没有值

切片不能相互比较,只可以与nil比较

使用append函数可以为切片增加元素

var x[]int
y:=[]int{6,7,8,9}
x=append(x,10)
x=append(x,1,2,3,4,5)
x=append(x,y...)

append函数接受至少两个参数,一个为任意类型的切片,另一个为该类型的值。返回的结果为同一类型的切片。这个返回的切片被赋值回了原切片。
切片在连续内存地址的大小就是切片的容量。容量可能会大于切片的长度,每次为切片添加一个元素时,都会将一个或者多个值添加到切片的尾部,容量也相应增加。如果最终所需的长度超出了容量大小,则append函数使用Go运行时分配一个有更大容量的切片,然后将原切片的内容拷贝到新的切片中,将需要添加的值加到新切片的末尾,最终返回新的切片。
个人感觉有点类似java中的ArrayList

创建指定容量的切片

x:=make([]int,5)//定义了一个长度为5,容量为5的整形切片
y:=make([]int,5,10)//创建了一个长度为5,容量为10的整形切片。

永远不要设置比长度小的容量

派生表达式从切片创建切片,类似于python,在中括号中指定起始偏移量和结束偏移量,使用:隔开。

x:=[]int{1,2,3,4}
y:=x[:2] //1,2
z:=x[1:] //2,3,4
d:=x[1:3] //2,3
e:=x[:]// 1,2,3,4

如果是取一个切片的子切片,那么并不会执行拷贝操作。两个切片会共享内存。这也意味着更改一个切片的元素会影响所有共享该元素的切片

如果需要创建一个独立于原切片的切片,可以使用copy函数

x:=[]int{1,2,3,4}
y:=make([]int,4)
num:=copy(y,x)
//y:1,2,3,4 num:4

3.3映射

var nilMap map[string][int] //此时声明了一个键为字符串,值为整形的映射类型
teams :=map[string][]string{
    "A":[]string{"a","b"},
    "B":[]string{"c","d"}
}
//如果已知了映射需要多少键值对,但不知道确切的值,可以使用make函数
ages:=make(map[int][]string,10)

//映射的读写
studentAge:=map[string]int{}
studentAge["a"]=12
studentAge["b"]=13
fmt.Pringln(studentAge["a"])
studentAge++
//映射中不存在对应的键就会返回零值
//go提供了逗号,ok模式
v,ok:=studentAge["c"] //如果ok为true那么代表映射中存在这个键
//删除映射中的键值对
delete(studentAge,"b")

3.4结构体

如果你有面向对象的语言编程经验,可能会想知道类和结构体之间的区别。区别很简单:Go中没有类,因为它不支持继承。
大多数语言都有结构体的概念,因此在Go中读写结构体的语法你应该很熟悉:

type person struct{
    name string
    age int
}
var p1 person
mike:=person{}
john:=person{

    "John",
    18
}

匿名结构体

vat person struct{
    name string
    age int
}
pet:=struct{
    name sting
    age int
}{
    name:"dog",
    age:2
}

判断结构体是否可以进行比较取决于结构体的字段。如果结构体中的所有字段都是可以比较的类型,那么结构体就可以比较;如果字段中有映射或者切片则不能比较