一、第一个程序
1.代码示例
package main
import (
"fmt"
)
func main(){
fmt.Println("hello world")
}
2.手动执行
go run xx.go
3.编译为可执行程序
go build -o xx.exe xx.go
4.代码格式调整
idea:Ctrl+Alt+L
命令行: gofmt -w xxx.go
注意:如果在windows开发后需要打包成在linux可执行程序每次都需执行以下三步
set ENABLECGO=0 //该配置不是必须,请根据实际配置
set GOARCH=amd64
set GOOS=linux
go build -o xxx xx.go
二、语法要求
1.命名规范
1) package 名称要与文件名相同
2) 变量、函数名 严格区分大小写,首字母大写为公有(public),小写为私有(private)
3) _表示省略返回值
2.变量定义
//局部变量定义必须被引用,否则程序会报错
var a = 1
var c int = 1
//:只可定义局部变量,不可定义全局
b := 1
//批量定义
var (
d = 1
f = 1
)
//常量定义,不可被改变
const FIRST_NUM = 1
//const结合iota
const (
//iota默认为0,SECOND_NUM值为0
SECOND_NUM = iota
//定义iota后,下面的变量可不主动赋值,默认会根据iota+=1进行赋值,THREE_NUM值为1
THREE_NUM
//这里iota会遵从iota+=1的原则变为2,然后乘以10,最后赋值为20
FOUR_NUM = iota * 10
/*这里iota的值增长规则不变,还是iota+=1,这里iota值为3,由于上一步附加了*10的规则,
这里FIVE_NUM值为30*/
FIVE_NUM
)
3.变量转换
package main
import (
"fmt"
"strconv"
)
func main(){
//类型转换需要进行显示的转换
var i = 100
var fi = float32(i)
fmt.Println(fi)
fmt.Printf("fi的类型为:%T",fi)
fmt.Println()
//int转字符串,参数一表示要转换的值,参数2表示转换的结果为几进制
var strNum = strconv.FormatInt(10,10)
fmt.Println(strNum)
fmt.Printf("strNum的类型为:%T",strNum)
fmt.Println()
//字符转转int,参数一为要转换的值,参数二为转换的结果为几进制,
//参数三bitSize指定结果必须能无溢出赋值的整数类型,0、8、16、32、64 分别代表 int、int8、int16、int32、int64
var intNum, _ = strconv.ParseInt(strNum,2,0)
fmt.Println(intNum)
fmt.Printf("strNum的类型为:%T",intNum)
fmt.Println()
}
4.指针
package main
import "fmt"
func changeValue1(p *int) {
//*p 指向地址存储的值
*p = 10
}
func changeValue2(p int) {
//p为局部变量,会创建新的地址
p = 100
}
func main() {
var a = 1
//&a 获取a变量的指针地址
changeValue1(&a)
changeValue2(a)
fmt.Println(a) //最终结果为10
//指针类型的变量同样有地址,因此出现多重指针
var pp = **int
var p = &a
pp = &p
}
//make和new的区别
//make和new都是用来申请内存的
//make是给map、slice、chan进行内存申请的,返回的是对象本身。
//new是给string、int等基本数据类型进行内存申请的,返回的是对应的指针类型,很少用
5.函数返回值
package main
import (
"fmt"
)
//无参数返回
func foo1(var1 int,var2 string) {
fmt.Println("----foo1----")
fmt.Println(var1,var2)
}
//返回一个参数
func foo2(var1 int,var2 string) int {
fmt.Println("----foo2----")
fmt.Println(var2)
return var1
}
//返回多个参数
func foo3(var1 int,var2 string) (int,string) {
fmt.Println("----foo3----")
return var1,var2
}
//返回多个同类型参数,并对参数命名
func foo4(var1,var2 int) (r1,r2 int) {
fmt.Println("----foo4----")
fmt.Println("r1=",r1,",r2=",r2)
//当给返回参数命名后,该返回结果会默认为整个函数的局部变量,并赋予默认值.
//若返回参数命名后可直接使用 return r1,r2,也可直接return
return var1,var2
}
func main(){
foo1(100,"无参数返回")
foo2Num := foo2(100,"返回一个参数")
fmt.Println(foo2Num)
foo3Num, foo3Str := foo3(100, "返回多个参数")
fmt.Println(foo3Num, foo3Str)
foo4Num1, foo4Num2 := foo4(1,2)
fmt.Println(foo4Num1, foo4Num2)
//_表示丢弃返回结果,直接垃圾回收
_,_ = foo4(1,2)
}
6.init函数和import的导包流程
import->const->var->init->main
7.import 导包
package main
//两个包不可相互依赖,例如:
//A依赖B,B依赖A,如果出现该情况会报import cycle not allowed的错误
import (
//正常导包
"fmt"
//匿名导包,只会默认调用包内的init函数,其他函数无法调用
_ "xxx"
//别名导包,可以使用别名进行保内的函数调用
mylib "xxx"
//本地导包,无需使用别名,直接使用函数名即可调用保内函数
. "xxxx"
)
8.defer关键字 (最后执行)
package main
import "fmt"
func return1() int {
fmt.Println("--------return 1----------")
return 1
}
func return2() int {
fmt.Println("--------return 2----------")
return 2
}
func execReturn() int {
defer return1()
//这里return 分为执行函数,返回结果两部,defer语句在这两步中间执行
return return2()
}
func main() {
defer fmt.Println("defer表示该语句最后执行,我相当于java的finally")
defer fmt.Println("我是第二个defer,defer是先进后出,因此我不能最后打印")
fmt.Println("我想最后执行")
fmt.Println(execReturn())
}
9.数组以及slice(动态数组)
package main
import "fmt"
//数组,值传递无法修改原数组的值
func printArray1(array [4]int) {
fmt.Println("普通数组")
for index, value := range array {
fmt.Println("index=", index, "value=", value)
}
}
//slice(动态数组),引用传递
func printArray2(array []int) {
fmt.Println("slice-动态数组")
for index, value := range array {
fmt.Println("index=", index, "value=", value)
}
array[1]=1000
}
func main() {
//定义数组
var array1 [4]int
var array2 = [4]int{1, 2, 3, 4}
var array3 = []int{1, 2, 3, 4}
printArray1(array1)
printArray1(array2)
printArray2(array3)
fmt.Println("slice可以在函数中修改值")
for index, value := range array3 {
fmt.Println("index=", index, "value=", value)
}
}
10.slice是使用注意事项
package main
import "fmt"
func printArray(array []int) {
fmt.Println("-------------分割线------------")
for index, value := range array {
fmt.Println("index=", index, "value=", value)
}
}
func main() {
//slice声明的方式
//方式一:声明一个slice,并非配两个空间,值为1,2
array1 := []int{1, 2}
printArray(array1)
//方式二:声明一个slice,未分配空间,通过append分配空间并增加数值,默认值为nil
var array2 []int
printArray(array2)
//方式三:通过make创建一个slice为slice分配指定大小空间,并设置初始扩容的cap值为10
//如果不传入cap,初始cap与len相同
//当len的大小超过cap时,cap会进行2倍扩容,当cap的数字大于1024后每次扩容以1.25倍进行扩容
var array3 = make([]int, 1, 10)
printArray(array3)
if array3 == nil {
fmt.Println("slice为nil")
} else if len(array3) == 10 {
fmt.Println("slice长度为10")
} else {
fmt.Println("slice不为nil")
}
//slice的使用
//slice截取数组
array4 := make([]int, 0)
//追加数组元素
array4 = append(array4, 1)
array4 = append(array4, 2)
array4 = append(array4, 3)
array4 = append(array4, 4)
//删除数组元素,表示将下标为1的元素删除,然后用下表为2的元素进1
array4 = append(array4[:1], array4[2:]...)
fmt.Println(len(array4))
printArray(array4)
//通过截取数组进行赋值,传递的是值引用,不是值,这里与python的规则不同,python传递的是值
//如果想要值传递需要使用copy函数
//在截取数据时,会以cap的数量为限定进行截取,比如len为3,cap为6你可以截取6个元素而不是3个
//在截取数据前当原数组未进行删除时,大于len元素默认会赋值为0
//如果原数组有进行删除,大于len的元素会以原数组未删除前下标的元素进行赋值不在为0
fmt.Println(len(array4),cap(array4),&array4)
array5 := array4[0:4]
fmt.Println(len(array5),cap(array5),&array5)
array5[0] = 100
printArray(array4)
printArray(array5)
var array6 = make([]int,3)
//通过copy进行slice深拷贝时,array6必须已分配等同的空间,否则会报错
copy(array6, array4)
array6[1] = 200
printArray(array6)
}
11.map使用
package main
import (
"fmt"
)
//遍历
func printMap(myMap map[string]string) {
for key, value := range myMap {
fmt.Println("key=", key, ",value=", value)
}
}
//删除
func deleteMap(myMap map[string]string, key string) {
delete(myMap, key)
}
//新增
func addMap(myMap map[string]string, key string, value string) {
myMap[key] = value
}
//修改
func updateMap(myMap map[string]string, key string, value string) {
myMap[key] = value
}
func main() {
//map的声明方式
//方式一
var map1 map[string]string
if map1 == nil {
fmt.Println("map为空")
}
//方式二
map2 := make(map[string]string, 10)
map2["one"] = "first"
//方式三
map3 := map[string]string{
"one": "first",
"two": "second",
}
deleteMap(map3,"one")
printMap(map1)
printMap(map2)
printMap(map3)
}
12.struct(结构体)
package main
import "fmt"
// User 自定义结构体
type User struct {
name string
age int
}
//结构提函数传递为值传递,因此需要设置指针专递才可修改结构体属性
func changeUser(user *User) {
user.age = 100
}
//类比于上方法,区别在于该方法属于struct结构体的方法,结构液体传递在这里同意规范使用指针传递
//如果值传递,方法内对该结构体值进行修改不可同步至方法外边指针
func (u *User)ChangeUser(){
u.age=10
}
func main() {
//定义结构体方式
//方式一
var user User
user.name = "名字"
user.age = 24
//方式二
var user1 = User{name:"名字",age:24}
//方式三
var user2 = User{"名字",24}
fmt.Println(user)
fmt.Println(user1)
fmt.Println(user2)
changeUser(&user)
fmt.Println(user)
//匿名结构体定义
var u struct{
Name string
}
u.Name="222"
fmt.Println(u)
}
13.interface
interface更多使用,请参考面向对象多态
package main
import "fmt"
//interface{}是万能数据类型
func myFunc(arg interface{}) {
fmt.Println("arg =", arg)
//校验数据类型
value, result := arg.(string)
if result {
fmt.Println("是字符串", value)
} else {
fmt.Println("不是字符串", value)
}
}
func main() {
myFunc(100)
myFunc("string")
}