go语言基本语法1
Posted 尚墨1111
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了go语言基本语法1相关的知识,希望对你有一定的参考价值。
文章目录
go
Go语言开发的开源项目,其中包括 Docker、Go-Ethereum、Thrraform 和 Kubernetes。
Go类似于Java,是编译型语言,自带编译器
1 Go基础
新版本的go 都是基于 go module 创建项目
Go.mod是Golang1.11版本新引入的官方包管理工具用于解决之前没有地方记录依赖包具体版本的问题,方便依赖包的管理。Modules和传统的GOPATH不同,不需要包含例如src,bin这样的子目录,一个源代码目录甚至是空目录都可以作为Modules,只要其中包含有go.mod文件。
Go.mod其实就是一个Modules,关于Modules的官方定义为:
Modules是相关Go包的集合,是源代码交换和版本控制的单元。go命令直接支持使用Modules,包括记录和解析对其他模块的依赖性。Modules替换旧的基于GOPATH的方法,来指定使用哪些源文件。
1.1 基本概念
【import _ 包路径】只是引用该包,仅仅是为了调用init()函数,所以无法通过包名来调用包中的其他函数,下划线在代码意思是忽略这个变量
1.1.2 值类型:
bool
int(32 or 64), int8, int16, int32, int64
uint(32 or 64), uint8(byte), uint16, uint32, uint64
float32, float64
string,字符串底层是一个byte数组,所以可以和[]byte类型相互转换。字符串是不能修改的
complex64, complex128
array -- 固定长度的数组
1.1.3 引用类型:(指针类型)
slice -- 序列数组(最常用)
map -- 映射
chan -- 管道
1.1.4 Go语言声明方式:
var(声明变量), const(声明常量), type(声明类型) ,func(声明函数)。
1.1.5 强制类型转换:
T(表达式),T表示要转换的类型。表达式包括变量、复杂算子和函数返回值等.
1.1.6 格式化输出
1.2 命名规范
1.2.1 包名、文件名
-
包名为全小写单词, 不使用复数,不使用下划线。尽可能简短。
package domain package main
-
文件名为全小写单词,使用 “_” 分词。
approve_service.go
-
测试文件必须以
_test.go
结尾。
1.2.2 变量名
-
变量、类型、函数名、结构命名遵循驼峰法。大写字母开头=public,小写字母开头=private
type UserController struct func isValidNumber(s string)
局部变量、函数参数的命名全部采用 lowerCamelCase。我们尽量让局部变量和函数参数的命名意义明确。
func Open(driverName, dataSourceName string) (*DB, error)
- 常量命名全部大写,单词间用下划线隔开,力求语义表达完整清楚,不要嫌名字长。
MAX_STOCK_COUNT
- Golang中没有专门的枚举类型(enum),通常使用一组常量来表示,为了更好的区分不同的枚举类型值,使用完整的前缀加以区分:
type PullRequestStatus int const ( PULL_REQUEST_STATUS_CONFLICT PullRequestStatus = iota PULL_REQUEST_STATUS_CHECKING PULL_REQUEST_STATUS_MERGEABLE )
-
对于只在本文件中有效的顶级变量、常量,应该使用 “_” 前缀,避免在同一个包中的其他文件中意外使用错误的值。例如:
var (
_defaultPort = 8080
_defaultUser = "user"
)
- 若变量、常量为 bool 类型,则名称应以 Has、Is、Can 或 Allow 开头:
var isExist bool
var hasConflict bool
var canManage bool
var allowGitHook bool
- 如果模块的功能较为复杂、常量名称容易混淆的情况下,为了更好地区分枚举类型,可以使用完整的前缀:
type PullRequestStatus int
const ( PULL_REQUEST_STATUS_CONFLICT PullRequestStatus = iota PULL_REQUEST_STATUS_CHECKING PULL_REQUEST_STATUS_MERGEABLE
)
1.2.3 函数、方法名
- 函数、方法(结构体或者接口下属的函数称为方法)命名规则: 动词 + 名词。
- 若函数、方法为判断类型(返回值主要为 bool 类型),则名称应以 Has、Is、Can 或 Allow 等判断性动词开头:
func HasPrefix(name string, prefixes []string) bool ...
func IsEntry(name string, entries []string) bool ...
func CanManage(name string) bool ...
func AllowGitHook() bool ...
1.2.4 结构体、接口名
- 结构体命名规则:名词或名词短语。
- 接口命名规则:以 ”er” 作为后缀,例如:Reader、Writer。接口实现的方法则去掉 “er”,例如:Read、Write。
type Reader interface Read(p []byte) (n int, err error)
// 多个函数接口
type WriteFlusher interface Write([]byte) (int, error) Flush() error
1.3 数组 array
数组定义:var a [len]int,比如:var a [5]int
多维数组:var arr0 [5][3]int
var arr1 [2][3]int = [...][3]int1, 2, 3, 7, 8, 9
//数组遍历test
var myString [5]int = [5]int1, 2, 3, 4, 5
for i := 0; i < len(myString); i++
fmt.Print(myString[i], ",")
fmt.Println()
for index, value := range myString
fmt.Print(index, ":", value, ",")
fmt.Println()
// 二维数组遍历
var multiString [3][2]int = [...][2]int1, 2, 3, 4, 5, 6
for k1, v1 := range multiString
for k2, v2 := range v1
fmt.Printf("(%d,%d)=%d,", k1, k2, v2)
fmt.Println()
1.4 切片 slice
切片跟数组的区别在于 Type 前的“ [] ”中是否有数字,为空,则代表切片,否则则代表数组。因为切片是长度可变的
var slice []type = make([]type, len, cap)
var slice []type = []type1,2,3,4
// 切片test
var slice = []int1, 2, 3, 4
var slice1 = make([]int, 4)
fmt.Printf("%v", slice) // [1 2 3 4]
fmt.Printf("%v", slice1)// [0 0 0 0]
原理:
假想每次传参都用数组,每次数组都要被复制一遍。消耗掉大量的内存。——函数传参用数组的指针。
函数传参问题:原数组的指针指向更改了,那么函数里面的指针指向都会跟着更改
切片优势:切片的指针和原来数组的指针是不同的
1.5 指针
指针地址、指针类型、指针取值
&arrayA //& 得到数组的内存地址,取地址
*[]int //* 获取内存地址对应值,取值
new函数得到的是一个类型的指针
a := new(int)//a := *int
make也是用于内存分配的,区别于new,它只用于slice、map以及chan的内存创建
//用指针修改值
var num = 3
var ptr = &num
*ptr = 6
fmt.Println(num) // 6
1.6 集合 map
map是一种无序的基于key-value的数据结构,Go语言中的map是引用类型,必须初始化才能使用。
//maptest: map[keyType]valueType
var myMap map[string]int = make(map[string]int, 3)
myMap1 := make(map[string]int, 3)
myMap["liming"] = 12
myMap1["zhangming"] = 18
fmt.Println(myMap["liming"])
val, ok := myMap1["zhangming"]//判断集合是否包含某key
fmt.Println(val, ok)//18 true
//遍历map
for k, v := range myMap
fmt.Print(k, "_", v)
1.7 结构体 struct
1.7.1 关键字type,实现自定义类的操作
// typetest
type MyInt int //自定义一种新类型叫MyInt
type NewInt = int //给int起一个小名叫NewInt
type person struct
name string
age int
like map[string]string
have []int
1.7.2 正常操作
var myPerson person
myPerson.name = "Lily"
myPerson.age = 20
myPerson.have = []int1, 2, 3, 4, 5
myPerson.like = map[string]string
"run": "yes",
"swim": "yes",
"bicycle": "yes",
fmt.Printf("%v", myPerson) // Lily 20 map[bicycle:yes run:yes swim:yes] [1 2 3 4 5]
1.7.3 利用指针实现结构体
//利用指针进行新建
var p = new(person) //new是新建了一个指针
p.name = "lucy"
fmt.Printf("%v", *p)//lucy 0 map[] []
//&
var person1 = &person
name: "Make",
fmt.Printf("%v", person1)//&Make 0 map[] []
1.7.4 匿名结构体
var car struct
Name string
Speed int
car.Speed = 120
car.Name = "BMW"
fmt.Printf("%v", car)
1.7.5 实现构造函数
type Student struct
name string
age int
subject string
func newStudent(name string, age int, subject string) *Student
return &Student
name: name,
age: age,
subject: subject,
func main()
student := newStudent("sommer", 17, "math")
fmt.Printf("%#v\\n", student)//&main.Studentname:"sommer", age:17, subject:"math"
1.7.6 方法——绑定
func (接收者变量 接收者类型) 方法名(参数列表) (返回参数)
函数体
func (student Student) read(book string)
fmt.Println(student.name, "读", book)
指针方法原值,拷贝方法不改变原值
注意:
当传递的是值拷贝类型时,不能传递指针*person和值&person
当传递的是指针类的时候,指针类型和值类型的变量均可相互调用
func main()
student.changSubject("history")
fmt.Printf("%#v\\n", student)//&main.Studentname:"sommer", age:17, subject:"history"
student.changSubject2("history")
fmt.Printf("%#v\\n", student)//&main.Studentname:"sommer", age:17, subject:"math"
func (student *Student) changSubject(newSubject string)
student.subject = newSubject
func (student Student) changSubject2(newSubject string)
student.subject = newSubject
1.7.7 嵌套匿名结构体——实现继承
所有的内置类型和自定义类型都是可以作为匿名字段去使用
func main()
myStudent := Student
name: "Jack",
age: 18,
subject: "English",
Person: Person//匿名结构体直接嵌套,如下如果是*Person,那么这里应该是&Person
hight: 180,
,
fmt.Printf("%#v\\n", myStudent)//main.Studentname:"Jack", age:18, subject:"English", Person:main.Personhight:180
type Student struct
name string
age int
subject string
Person// 对应的如果这里是*Person
type Person struct
hight int
2 流程控制
2.1 if
if a < 20
fmt.Printf("a 小于 20\\n" )
else
fmt.Printf("a 不小于 20\\n" )
2.2 switch
//Go里面switch默认相当于每个case最后带有break,匹配成功自动跳出整个switch,但是可以使用fallthrough强制执行后面的case代码
//如果switch没有表达式,它会匹配true
switch i := x.(type) // 带初始化语句
case nil:
fmt.Printf(" x 的类型 :%T\\r\\n", i)
case int:
fmt.Printf("x 是 int 型")
case float64:
fmt.Printf("x 是 float64 型")
case func(int) float64:
fmt.Printf("x 是 func(int) 型")
case bool, string:
fmt.Printf("x 是 bool 或 string 型")
default:
fmt.Printf("未知型")
2.3 select
2.4 for——没有while
基本三种语法
s := "abc"
for i, n := 0, len(s); i < n; i++ // 常见的 for 循环,支持初始化语句。
println(s[i])
n := len(s)
for n > 0 // 替代 while (n > 0)
println(s[n]) // 替代 for (; n > 0;)
n--
for // 替代 while (true)
println(s) // 替代 for (;;)
2.5 range
for 循环的 range 格式可以对 slice、map、数组、字符串等进行迭代循环。
for key, value := range oldMap
newMap[key] = value
1st value | 2nd value | ||
---|---|---|---|
string | index | s[index] | unicode, rune |
array/slice | index | s[index] | |
map | key | m[key] | |
channel | element |
3 函数
3.1 基本语法
func test(x, y int, s string) (int, string)
// 类型相同的相邻参数,参数类型可合并。 多返回值必须用括号。
n := x + y
return n, fmt.Sprintf(s, n)
// 利用别名操作
// 定义函数类型。
type FormatFunc func(s string, x, y int) string
func format(fn FormatFunc, s string, x, y int) string
return fn(s, x, y)
3.2 参数
在默认情况下,Go 语言使用的是值传递,即在调用过程中不会影响到实际参数。map、slice、chan、指针、interface默认以引用的方式传递。
可变参数在参数后加上“…”即可,
其中args是一个slice,我们可以通过arg[index]依次访问所有参数,通过len(arg)来判断传递参数的个数.
func myfunc(args ...int) //0个或多个参数
func add(a int, args…int) int //1个或多个参数
func add(a int, b int, args…int) int //2个或多个参数
用interface传递任意类型数据是Go语言的惯例用法,而且interface是类型安全的。
func myfunc(args ...interface)
使用 slice 对象做变参时,必须展开。(slice...)
package main
import (
"fmt"
)
func test(s string, n ...int) string
var x int
for _, i := range n
x += i
return fmt.Sprintf(s, x)
func main()
s := []int1, 2, 3
res := test("sum: %d", s...) // slice... 展开slice
println(res)
3.3 闭包
3.3.1 函数变量
func square(x int)
println(x * x)
- 直接调用:
square(1)
- 把函数当成变量一样赋值:
s := square
;接着可以调用这个函数变量:s(1)
。s就是这个函数变量
注意:这里square
后面没有圆括号,调用才有。
3.3.2 闭包
闭包 = 函数 + 相关引用环境,组合而成的实体,闭包对它作用域上部的变量可以进行修改,修改引用的变量会对变量进行实际修改
str := "hello world"
foo := func()
str = "hello dude" // 匿名函数中并没有定义 str,str 的定义在匿名函数之前,str 就被引用到了匿名函数中形成了闭包
foo()//执行闭包,此时 str 发生修改,变为 hello dude。
把整个匿名函数当做函数变量,用另一个函数进行整合,就形成了常见的模式
// 1
func() int //无输入参数,返回int
var x int
func()
x++
return x
// 2 整合
func() int
var x int
return func() int
x++
return x
// 3 作为另一个函数的返回值
func incr() func() int
var x int
return func() int
x++
return x
i := incr() //通过把这个函数变量赋值给 i,i 就成为了一个闭包。i 保存着对 x 的引用
printlngo语言基本语法1