Golang基本语法
Golang
变量定义
变量类型写在变量名之后
编译器可推测变量类型
没有char ,只有rune
原生支持复数类型
`
package main
import (
"fmt"
"math"
)
var ( //在外部定义是包内变量,并不是全局变量,所有函数都能用。在外部不能用:来初始化值
aa = 12
bb = "xc"
)
var cc = true //变量可都放在var的括号内
func variableZeroValue() { //初始化会赋初值
var a int
var s string
fmt.Println(a,s) //0
fmt.Printf("%d %s\n",a, s) //0
fmt.Printf("%d %q\n", a, s) //0 ""
}
func variableInitialValue() {
var a, b int = 3, 4 //多个数赋初值
var s string = "abc"
fmt.Println(a, b, s) //3 4 abc
}
func variableTypeDeduction() {
var a, b, c, s = 3, 4, true, "abd" //能自动判断类型,从而进行赋值
fmt.Println(a, b, c, s) //3 4 true abd
}
func variableShorter() {
a, b, c, s := 3, 4, true, "asdf" //:和功能上面一样的,初始化时候有用
fmt.Println(a, b, c, s) //3 4 true asdf
}
func triangle() { //类型需要强制转换,不能隐式转换
var a, b int = 3, 4
var c int
c = int(math.Sqrt(float64(a*a+b*b)))
fmt.Println(c) //5
}
func consts() { //常量,可作为任何数值使用,不用强制转换,必须赋值
const filename = "name.vs"
const a, b = 3, 4
var c int
c = int(math.Sqrt(a*a+b*b))
fmt.Println(c) //5
}
func enums() { //枚举类型,可用const定义,iota是自增
const(
java = iota
python
golang
javascript
)
fmt.Println(java, python, golang, javascript) //0 1 2 3
const(
k = 1 << (10*iota)
kb
mb
gb
)
fmt.Println(k, kb,mb, gb) //1 1024 1048576 1073741824
}
func main() {
fmt.Println("hello world") //hello world
variableZeroValue()
variableInitialValue()
variableTypeDeduction()
variableShorter()
fmt.Println(aa,bb,cc) //12 xc true
triangle()
consts()
enums()
}
`
条件语句if
- if和else if后面没有括号
`
package main
import (
"io/ioutil"
"fmt"
)
func main() {
const filename = "a.txt"
content, err := ioutil.ReadFile(filename)
if err != nil {
fmt.Println(err)
} else {
fmt.Printf("%s\n",content)
}
//上下两个是等价的,if条件里可以赋值,下面这个con和error的变量作用域在if里
if con, error := ioutil.ReadFile(filename);err != nil {
fmt.Println(error)
} else {
fmt.Printf("%s\n",con)
}
}
`
循环语句for
- for后面条件没有括号
`
package main
import (
"fmt"
"strconv"
"os"
"bufio"
)
func convertToBin(n int) string {
result := ""
for ; n > 0; n /= 2 { //可以省略初始条件
lsb := n%2
result = strconv.Itoa(lsb) + result;
}
return result
}
func printFile(filename string) {
file, err := os.Open(filename)
if err != nil {
panic(err) //报错处理
}
scanner := bufio.NewScanner(file)
for scanner.Scan() {//可以省略初始条件和递增条件
fmt.Println(scanner.Text())
}
}
func forever() {
for { //死循环
fmt.Println("ads")
}
}
func main() {
const filename = "a.txt"
fmt.Println(
convertToBin(13), //1101
)
printFile("a.txt")
forever()
}
`
函数
返回值类型写在最后面
可返回多个值
函数作为参数
没有默认参数,可选参数
`
package main
import (
"fmt"
"math"
)
func div(a, b int) (int, int) { //能返回多个参数,相同类型的参数,可公用一个类型
return a/b, a%b
}
func apply(op func(int, int) int, a, b int) int { //参数为匿名函数
return op(a, b)
}
func sum(numbers ...int) int { //可变参数列表
s := 0
for i := range numbers {
s += numbers[i]
}
return s
}
func main() {
fmt.Println(
div(13,4), //3 1
)
fmt.Println(
apply(func(a int, b int) int {
return int(math.Pow(float64(a),float64(b)))
},3,4),
) //81
fmt.Println(sum(1,2,3,4,5,6,7,8,9,10)) //55
}
`
指针
- 指针不能运算
`
package main
import "fmt"
func swap1(a, b *int) {
*a,*b = *b,*a
}
func swap2(a, b int)(int, int) {
return b, a
}
func main() {
a, b, c, d:= 1, 2, 1,2
swap1(&a, &b)
fmt.Println(a, b) //2 1
fmt.Println(swap2(c, d)) //2 1
}
`
数组
[10]int和[20]int是不同类型
调用func f(arr [10]int)会拷贝数组
在go语言中一般不直接使用数组,使用切片
`
package main
import "fmt"
func printArray(arr [5]int) {
for i := 0; i < len(arr); i++ {
fmt.Println(arr[i])
}
for i := range arr {
fmt.Println(arr[i])
}
for i, v := range arr { //索引和值
fmt.Println(i, v)
}
}
func main() {
var arr1 [5]int
arr2 := [3]int{1,2,3}
arr3 := [...]int{1,2,3,4,5}
var grid [2][3]int
fmt.Println(arr1,arr2,arr3,grid)
//[0 0 0 0 0] [1 2 3] [1 2 3 4 5] [[0 0 0] [0 0 0]]
printArray(arr1)
printArray(arr3)
}
`
Map
- 使用range遍历key ,或者遍历key, value对
- 不保证遍历顺序,如需顺序,需手动对key排序
- 使用len获得元素个数
- map使用哈希表,必须可以比较相等
- 除了slice, map, function的内建类型都可以作为key
- Struct类型不包含上述字段,也可作为key
`
package main
import "fmt"
func main() {
m1 := map[string]string {
"qwe":"qe",
"qq": "ww",
}
m2 := make(map[string]int) //m2 == empty map
var m3 map[string]int //m3 == nill
fmt.Println(m1,m2,m3) //map[qwe:qe qq:ww] map[] map[]
for k, v := range m1 {
fmt.Println(k,v)
}
//qwe qe
//qq ww
qwName, ok := m1["qwe"] //有值ok为true,反之为false
fmt.Println(qwName, ok) //qe true
if ok {
fmt.Println(qwName) //qe
fmt.Println(m1["asa"]) //空
}
delete(m1, "qwe") //删除key为"qwe"的键值对
fmt.Println(m1) //map[qq:ww]
}
`
切片splice
添加元素时如果超越cap ,系统会重新分配更大的底层数组
由于值传递的关系,必须接收append的返回值
S = append(S, val)
`
package main
import "fmt"
func printSlice(s []int) {
fmt.Printf("slice=%v len=%d cap=%d\n", s, len(s), cap(s))
}
func main() {
arr := [...]int{0,1,2,3,4,5,6,7}
s1 := arr[2:6]
fmt.Println(s1) //[2 3 4 5] 左闭右开
s2 := s1[3:5]
fmt.Println(s2) //[5 6] 出现了s1中没有出现的值,因为有cap的缘故
s3 := s1[:3]
s1[0] = 100
fmt.Println(arr) //[0 1 100 3 4 5 6 7] slice中改变会导致原数组中的值改变
fmt.Println(s1) //[100 3 4 5]
fmt.Println(s3) //[100 3 4]
s4 := append(s1,10)
fmt.Println(s4) //[100 3 4 5 10]
s5 := append(s4, 11)
fmt.Println(s5) //[100 3 4 5 10 11]
s6 := append(s5, 12)
fmt.Println(s6) //[100 3 4 5 10 11 12]
s7 := append(s6,20)
fmt.Println(s7) //[100 3 4 5 10 11 12 20]
fmt.Println(s1) //[100 3 4 5]
//slice的创建方式
var s []int
for i := 0; i < 100 ; i++ {
s = append(s, i)
}
fmt.Println(s) //[1,2,3,4.......99]
a1 := []int{2,3,4,5}
printSlice(a1) //slice=[2 3 4 5] len=4 cap=4
a2 := make([]int, 16)
printSlice(a2) //slice=[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] len=16 cap=16
a3 := make([]int, 16, 31)
printSlice(a3) //slice=[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] len=16 cap=31
copy(a2, a1)//拷贝
printSlice(a2) //slice=[2 3 4 5 0 0 0 0 0 0 0 0 0 0 0 0] len=16 cap=16
a2 = append(a2[:2],a2[3:]...) //删除其中某一个元素
printSlice(a2) //slice=[2 3 5 0 0 0 0 0 0 0 0 0 0 0 0] len=15 cap=16
//删去头部元素 ,因为是头部元素,pre指针只会往后移动,不会往前,所以,cap会少1,如果是尾部元素,cap不变
a2 = a2[1:]
printSlice(a2) //slice=[3 5 0 0 0 0 0 0 0 0 0 0 0 0] len=14 cap=15
a2 = a2[:len(a2)-1] //删去尾部元素
printSlice(a2) //slice=[3 5 0 0 0 0 0 0 0 0 0 0 0] len=13 cap=15
}
`
结构体
- 首字母大写是public,能被外部访问
- 首字母小写是private,不能被外部访问
- 命名一般都是CamelCase
`
package main
import (
"fmt"
)
type treeNode struct {
value int
left, right *treeNode
}
//---------
//这两个写法是一样的,(node treeNode)放在前面是将root作为接收者
func (node treeNode) print() { //为结构体定义的方法
fmt.Println(node.value)
}
func print1(node treeNode) {
fmt.Println(node.value)
}
//-----------
//因为go语言都是值传递,所以要改变值,得用引用传递
//只有指针才可以改变结构内容
func (node *treeNode) setValue(value int) {//为结构体定义的方法
node.value = value
}
//使用了自定义工厂函数,注意返回了局部变量的地址,go中不算错
func createTreeNode(value int) *treeNode {
return &treeNode{value: value}
}
func main() {
var root treeNode
root = treeNode{value: 3}
root.left = &treeNode{} //因为left是个指针,所以得取地址
root.right = &treeNode{4, nil, nil}
root.left.right = new(treeNode)
root.right.left = createTreeNode(5)
root.right.left.print() //5
root.right.left.setValue(9)
root.right.left.print() //9
nodes := []treeNode {
{value:3},
{},
{6,nil,&root},
}
fmt.Println(nodes) //[{3 <nil> <nil>} {0 <nil> <nil>} {6 <nil> 0xc00000a080}]
}
`