Go语言基本语法|青训营笔记

94 阅读6分钟

这是我参与「第三届青训营 -后端场」笔记创作活动的第1篇笔记

go语言的特点

Go 具有表现力、简洁、干净和高效。它的并发机制使编写充分利用多核和联网机器的程序变得容易,而其新颖的类型系统支持灵活和模块化的程序构建。

Go语言的主要特征:

  • 1.自动立即回收
  • 2.更丰富的内置类型
  • 3.函数多返回值。

基本语法

hello World

package main

import (
   "fmt"
)

func main() {
   fmt.Println("hello world")
}
  • 第一行package main代表这个文件属于main包的一部分,main包也就是程序的入口包。 第三行导入了标准库里面的FMT包。这个包主要是用来往屏幕输入输出字符串、格式化字符串。 import 下面是main函数,main函数里面调用了fmt.Println 输出helloword

var 关键字

package main

import (
   "fmt"
   "math"
)

func main() {

   var a = "initial"

   var b, c int = 1, 2

   var d = true

   var e float64

   f := float32(e)

   g := a + "foo"
   fmt.Println(a, b, c, d, e, f) // initial 1 2 true 0 0
   fmt.Println(g)                // initialapple

   const s string = "constant"
   const h = 500000000
   const i = 3e20 / h
   fmt.Println(s, h, i, math.Sin(h), math.Sin(i))
}
  • 使用 var 关键字是Go最基本的定义变量方式,有时也会使用到 := 来定义变量。
  • 操作符 := 快速变量声明。可以同时声明并初始化一个变量,不必声明一个具体类型的变量,Go语言可以从其初始化值推导其类型。
  • 变量e没有显示初始化,会赋零值,字符串会默认为空。
  • Go语言中的常量使用关键字 const 定义,用于存储不会改变的数据,常量是在编译时被创建的。
  • Go语言提供了大量内置的数值类型。不能在不同的类型之间进行二进制数值运算或比较操作。
  • 3e20是科学计数法 3*10^20
  • Math.Sin(x) 以弧度为单位的x的正弦值

if语句


import "fmt"

func main(){
   if 7%2==0 {
      fmt.Println("7 is even")
   }else {
      fmt.Println("7 is odd")
   }
//if optionalStatement1;booleanExpression1 {}
   if num:=8;num<0 {
      fmt.Println(num,"is negetive")
   }else if num<10{
      fmt.Println(num,"has 1 digit")
   }
}
  • if语句的大括号是强制性的,条件判断中的分号只有在可选语句optionalStatement出现的情况下需要。
  • 第一个if语句的num变量扩展到了if...elseif...语句中,因此他们在每一个分支中都是可见的。

for循环

package main

import "fmt"

func main(){
   i:=1
  //for booleanExpression{block}
  for{
  
      fmt.Println("loop")
      break
   }
   // for optionalPreStatement;booleanExpress;optionalPostStatement
   for j:=7;j<9;j++{
      fmt.Println(j)
   }
   for n:=9;n<5;n++ {
      if n%2==0 {
         continue
      }
      fmt.Println(n)
   }
   for i<=3 {
      fmt.Println(i)
      i=i+1
   }
}
  • Go 语言的for循环有3种形式,只有其中的一种使用分号。

switch循环


import (
   "fmt"
   "time"
)

func main(){
   a := 2
   //switch optionalStatement{
   switch a {
   //case expressionList1:
       //block
   case 1:
      fmt.Println("one")

   case 2:
      fmt.Println("two")
   case 3:
      fmt.Println("three")
   //default:bloakD
   default:
      fmt.Println("other")
}
   t:=time.Now()
   switch  {
   case t.Hour()<12:
      fmt.Println("1")
   default:
      fmt.Println("2")
   }

   }

  • 不同于c和java,go的switch语句不会自动向下贯穿,因此不必在每个case字句末尾添加break语句,需要case语句向下贯穿时可以显式调用fallthrough
  • 没有可选的表达式语句,编译器会把表达式语句设为true。意味着case语句的每一个表达式都必须计算为布尔类型。

range

package main

import "fmt"

func main() {
   nums := []int{2, 3, 4}
   sum := 0
   for i, num := range nums {
      sum += num
      if num == 2 {
         fmt.Println("index:", i, "num:", num) // index: 0 num: 2
      }
   }
   fmt.Println(sum) // 9

   m := map[string]string{"a": "A", "b": "B"}
   for k, v := range m {
      fmt.Println(k, v) // b 8; a A
   }
   for k := range m {
      fmt.Println("key", k) // key a; key b
   }
}

  • 对于一个slice或者一 个map的话,可以用range来快速遍历,可以使代码更加简洁。range遍历的时候,对于数组会返回两个值,第一 个是索引,第二个是对应位置的值。如果我们不需要索引的话,我们可以用下划线来忽略。

切片


import "fmt"

func main(){
   s:=make([]string,3)
   s[0]="a"
   s[1]="b"
   s[2]="c"
   fmt.Println("get:",s[2])
   fmt.Println("len:",len(s))

   s=append(s,"d")
   s=append(s,"e","f")
   //[a b c d e f]
   fmt.Println(s)

   c:=make([]string,len(s))
   copy(c,s)
   //[a b c d e f]
   fmt.Println(c)
//[c d e]
   fmt.Println(s[2:5])
  // [a b c d e]
   fmt.Println(s[:5])
   //[c d e f]
   fmt.Println(s[2:])

   good := []string{"g","o","o","d"}
   fmt.Println(good)

}

  • 切片不同于数组可以任意更改长度,然后也有更多丰富的操作。比如说我们可以用make来创建一个切片, 可以像数组-样去取值,使用append来追加元素。
  • 注意append的用法的话,你必须把append的结果赋值为原数组。
  • 因为slice的原理实际上是它有一个它存储了一个长度和一个容量,加一个指向一个数组的指针,在你执行append操作的时候,如果容量不够的话,会扩容并且返回新的slice。
  • slice此初始化的时候也可以指定长度。
  • slice拥有像python一样的切片操作,比如这个代表取出第二个到第五个位置的元素, 不包括第五个元素。不过不同于python,这里不支持负数索引。

map


import "fmt"

func main(){
   m:=make(map[string]int)
   m["one"]=1
   m["two"]=2
   //map[one:1 two:2]
   fmt.Println(m)
   //2
   fmt.Println(len(m))
   //1
   fmt.Println(m["one"])
   //0
   fmt.Println(m["unknow"])

   r,ok := m["unknow"]
   //0 false
   fmt.Println(r,ok)

   delete(m,"one")

   m2:=map[string]int{"one":1,"two":2}
   var m3 = map[string]int{"one":1,"two":2}
   fmt.Println(m2,m3)
}

  • map在其他编程语言里面,它可能可以叫做哈希或者字典。 map是实际使用过程中最频繁用到的数据结构。
  • 我们可以用make来创建一个空map,这里会需要两个类型,第一个是那个key的类型,这里是string另一个是value的类型这里是int。 我们可以从里面去存储或者取出键值对。可以用delete从里面删除键值对。
  • golang的map是完全无序的,遍历的时候不会按照字母顺序,也不会按照插入顺序输出,而是随机顺序。

结构体


import (
   "fmt"
)

type user struct{
   name string
   password string
}

func main(){
   a := user{name:"li",password:"1024"}
   b := user{"li","1024"}
   c :=user{name:"li"}
   c.password="1024"
   var d user
   d.name="wang"
   d.password="1024"

   fmt.Println(a,b,c,d)
//false
   fmt.Println(checkPassword(a,"haha"))
   //false
   fmt.Println(checkPassword2(&a,"haha"))

   a.resetPassword("2048")
   //true
   fmt.Println(a.checkPassword("2048"))

}
func checkPassword(u user,password string) bool{
   return u.password==password
}
func checkPassword2(u *user,password string) bool {
   return u.password==password
}

func (u *user)resetPassword(password string){
   u.password=password
}
func (u user)checkPassword(password string)bool{
   return u.password==password
}

  • 结构体是一种聚合的数据类型
  • 结构体定义需要使用 type 和 struct 语句。struct 语句定义一个新的数据类型,结构体中有一个或多个成员。type 语句设定了结构体的名称。

函数


import "fmt"

func add(a int,b int)int {
   return a+b
}
func add2(a,b int) int{
   return a+b
}
func add3(n int){
   n+=2
}
func add3ptr(n *int){
   *n+=2
}
func exists(m map[string]string,k string)(v string,ok bool){
   v,ok=m[k]
   return v,ok
}
func main(){
   res:=add(1,2)
   fmt.Println(res)

   v,ok:=exists(map[string]string{"a":"A"},"a")
   fmt.Println(v,ok)
   
   
n:=5
add3(n)
fmt.Println(n)//5
add3ptr(&n)
fmt.Println(n)//7

}

  • Golang 和其他很多语言不-样的是,变量类型是后置的。
  • Golang里面的函数原生支持返回多个值。在实际的业务逻辑代码里面几乎所有的函数都返回两个值,第一个是真正的返回结果,第二二个值是一个错误信息。