golang基础语法| 青训营

132 阅读9分钟

一、走进Go语言基础语法

1.Go语言的基本特点

(1)高性能、高并发:不需要寻找经过性能优化的第三方库,只需要使用标准的第三方库;

(2)语法易懂:不需要表达式括号、只有一个for循环;

(3)丰富的标准库:有功能完善的标准库,稳定性、兼容性好;

(4)完善的工具链:各种功能的实现都有工具能实现帮助;

(5)静态编译:只需要复制编译后的文件就可以执行,部署方便快捷;

(6)快速编译:编译速度很快;

(7)跨平台:多种操作系统都能运行;

(8)垃圾回收:无需考虑内存的分配释放

2.GO语言的变量类型:包括字符串、整数、浮点型、布尔型等

    其中字符串是内置类型,可以直接通过加号拼接,也可以直接用等于号比较两字符串

变量声明有两种方式:

    var name string = ""

    使用变量 := 等于值

var a = " initial" 

var b,c int = 1 , 2

var d = true 

var e float64

f := float32(e)

g := a + "foo" 

常量的定义就是把 var 改成 const,注意 go里面的常量没有确定类型,根据上下文自动确定

const s string = " constant"

const h = 500000000

const i = 3e20/h

if - else语句 :go语言里的if-else里的if后面没有括号,且后面必须接大括号:

if 7 % 2 == 0 {
    fmt.Println( " 7 is even" )
} else {
    fmt.Println( " 7 is old " )
}

循环:go语言中只有唯一的一种for循环,循环途中可以用break跳出,或者continue来继续循环

for{
    fmt.Println(" loop ")
    break
}
for n := 0; n < 5; n++ {
    if n % 2 == 0 {
        continue
    }
    fmt.Println(n)
}

switch分支结构:switch后的变量名,不需要括号。最大的不同点在于,go语言中的每一个case后面不需要加break,switch case后的语句不会一直往下执行的。

switch a {
    case 1:
        fmt.Println("one")
    case 2:
        fmt.Println("two")
}

数组:有编号且长度固定的元素序列。

var a [5]int 
b := [5]int{1,2,3,4,5}
var twoD [2][3]itn

切片:不同于数组,可以任意更改长度,操作更丰富。可以用make来创建一个切片,像数组一样去取值,使用append来追加元素。

slice实质上是存储了一个长度和容量,加上一个指向数组的指针,在执行append操作的时候,如果容量不够的话,会扩容并且返回新的slice。

s := make([]string , 3)
s = append(s , "d")
s = append(s , "e", "f")

map:是实际使用过程中最频繁用到的数据结构,可以用make来创建一个空 map,第一个是key的类型,第二个是value的类型。可以存储或者取出键值对,也可以用delete删除键值对。

golang的map是完全无序的,遍历的时候不会按照字母顺序,也不会按照插入顺序输出,而是随机

m := make(map[string]int)
m["one"] = 1
m["two"] = 2
delete(m,"one")

m2 := map[string]int{"one":1 , "two":2}

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

nums := []int{2,3,4}
for i,num := range nums {}

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

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

func add( a int , b int) int {
    return a + b
}
func exists(m map[string]string, k string) (v string , ok bool){
    v , ok = m[k]
    return v , ok
}

指针:golang里的支持的指针操作很有限,其一个用途就是对传入参数进行修改。

fun add2ptr( n *int){
    *n += 2
}
func main( ){
    add2tr(&n)
    fmt.Println(n) //7
}

结构体:结构体是带类型的字段的集合。可以用结构体的名称去初始化一个结构体变量,构造的时候需要传入每个字段的初始值。也可以用键值对的方式去指定初始值,这样可以只对一部分字段进行初始化。同样结构体也能支持指针,这也可以实现对结构体的修改。

type user struct{
    name string
    password string
}
func main(){
    a := user{name: "wang", password:"1024"}
    c :=user{name: "wang"}
    c.password = "1024"
}

结构体方法:golang里可以为结构体去定义一些方法,类似其他语言里面的类成员函数。实现结构体的方法也有两种写法,一种是带指针,一种是不带指针。区别在于,如果带指针的话,实际上就可针对这个结构体去做修改,如果不带指针的话,实际上操作的是一个拷贝,无法对结构体进行修改。

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

错误处理:go语言里使用一个单独的返回值来传递错误信息。go语言能够很新奇的知道哪个函数返回了错误,并且能用简单的if-else来处理错误。在函数中可以在返回值类型里面,加一个error,就代表这个函数可能会返回错误,因此在函数时限的时候,需要同时return两个值,如果出现错误的话就return nil和一个error,如果没有的话,就返回原本的结果和nil。

func findUser(users []user, name string) (v *user , err error){
    for _,u := range users{
        if u.name == name {
            return &u,nil
        }
    }
    return nil, errors.New("not found")
}

字符串格式化:在标准库的FMT里,有很多的字符串格式相关的方法,比如printf这个类似于C语言里的printf函数,不同的是,在go语言里,可以很轻松的用%v来打印任意类型的变量,而不需要区分数字字符串,也可以用%+v打印详细结果,%#v则更详细

type point struct{
    x,y int
}
func main(){
    fmt.Printf(" p = %v" , p) //p={1,2}
    fmt.Printf(" p = %+v" , p) //p={x:1 y:2}
    fmt.Printf(" p = %#v" , p) //p=main.point{x:1 , y:2}
}

JSON操作:go语言里的JSON操作非常简单,对于一个已有的结构体,我们可以什么都不做,只要保证每个字段的第一个字母是大写,也就是公开字段。那么这个结构体就能用JSON.marshaler去序列化,变成一个JSON的字符串。序列化之后的字符串也能够用JSON。unmarshaler去反序列化到一个空的变量里面。这样默认序列化出来的字符串的话,它的风格是大写字母开头,而不是下划线。

type userInfo struct {
    Name string
    Age  int 'json:"age"'
    Hobby []string
}
func main(){
    a := userInfo{Name:"wang", Age: 18, Hobby: []string{"Golang","TypeScript"}}
    buf,err := json.Marshal(a)
    fmt.Println(string(buf))
}

时间处理:go语言里最常用的就是time.now()来获取当前时间,也可以用time.date去构造一个带时区的时间。有很多方法来获取这个时间点的年月日时分秒,也能用sub去对两个时间进行减法,得到一个时间段

now := time.Now()
t := time.Date(2022,3,27,1,25,36,0,time.UTC)
t2 := time.Date(2022,3,27,2,30,36,0,time.UTC)
fmt.Println(t.Year(),t.Month(),t.Day(),t.Hour(),t.Minute())
diff := t2.Sub(t)
fmt.Println(diff)

数字解析:在go语言中,关于字符串和数字类型之间的转换都在STR conv这个包下。可以用parselnt或者parseFloat来解析一个字符串。也可以用Atio把一个十进制字符串转成数字,还可以用itoA把数字转成字符串,如果输入不合法,那么这些函数都会返回error。

import(
    "fmt"
    "strconv"
)
func main(){
    f,_ := strconv.ParseFloat("1.234",64)
    fmt.Println(f)//1.234
    n,_ := strconv.ParseInt("111",10,64)
    fmt.Println(n)//111

    n2,_ := strconv.Atoi("123")
    fmt.Println(n2)//123
    n2,error := strconv.Atoi("AAA")
    fmt.Println(n2,err)//"AAA":invalid syntax
}

进程信息:在go里面,能够用os.argv来得到程序执行的时候的指定的命令行参数。

思考:go语言和其他语言之间的不同有哪些?

在学习了基础语法之后,我去网络上查看了一些go语法的特点,总结如下:

  1. 并发性与轻量级线程(Goroutines):Go语言的最显著特点之一是其对并发编程的原生支持。Goroutines 是一种轻量级线程,可以高效地运行成百上千个并发任务,而不会造成过多的内存开销。它们通过通道(Channels)进行通信和同步,使并发编程变得更加简洁和安全。
  2. 垃圾回收(Garbage Collection):Go语言具有自动垃圾回收机制,它能够自动管理内存的分配和释放。这减轻了开发人员的负担,避免了常见的内存泄漏问题。
  3. 编译型语言:Go是一种编译型语言,代码在编译时被编译成机器码,从而在运行时执行更加高效。这使得Go语言在性能方面表现出色。
  4. 静态类型:Go是静态类型语言,每个变量在声明时必须指定其类型。这有助于在编译时发现类型相关的错误,并提供更好的代码可读性和安全性。
  5. 简洁的语法:Go语言的语法非常简洁,减少了不必要的符号和冗余代码。它鼓励使用清晰的命名和结构,以实现可读性更强的代码。
  6. 内置的工具链:Go语言附带了丰富的工具集,包括格式化工具、测试工具、性能分析工具等。这些工具使得开发、测试和优化代码变得更加方便。
  7. 依赖管理:Go语言在版本1.11及之后的版本中引入了模块化和依赖管理机制,使项目的依赖关系更加清晰和可管理。
  8. 跨平台支持:Go语言支持跨平台编译,使得可以在不同的操作系统上编写一次代码,并在不同的平台上进行编译和运行。
  9. 性能优化:Go语言的设计目标之一是提供高性能的运行时,这使得它在许多场景下比其他语言更具优势,特别是在并发编程方面。
  10. 网络编程 Go语言内置了对网络编程的支持,提供了标准库中的网络包,使得编写网络应用程序变得更加简单。