【Golang】一文学完 Golang 基本语法

Golang 下载

安装包链接:https://share.weiyun.com/InsZoHHu

IDE 下载:https://www.jetbrains.com/go/

第一个 golang 程序

Go 复制代码
package main

import "fmt"

func main() {
   fmt.Println("hello golang")
}

每个可执行代码都必须包含 Package、import 以及 function 这三个要素。

变量

主函数文件:

Go 复制代码
package main

import (
   "awesomeProject/package1"
   "fmt"
)

// 全局变量
var gStr string
var gInt int

func main() {
   // 局部变量
   var lStr string
   var lInt int

   gStr = "out"
   gInt = 100

   lStr = "in"
   lInt = 50

   fmt.Println(gStr)
   fmt.Println(gInt)
   fmt.Println(lStr)
   fmt.Println(lInt)
    
   // 包外函数
   package1.Fun()

   // 包外变量
   package1.Str = "good"
   fmt.Println(package1.Str)
}

package1 包的文件:

Go 复制代码
package package1

import (
   "fmt"
)

var Str string

func Fun() {
   fmt.Println("test")
}

注意:golang是以首字母大小写来区分对包外是否可见。

所以 Fun() 函数,Str,想要在 main 文件被访问,都首字母大写了。

数组,切片,字典

Go 复制代码
package main

import "fmt"

func main() {
   //数组初始化
   var strAry = [10]string{"aa", "bb", "cc", "dd", "ee"}

   //切片初始化
   var sliceAry = make([]string, 0)
   sliceAry = strAry[1:3]

   //字典初始化
   var dic = map[string]int{
      "apple":      1,
      "watermelon": 2,
   }

   // %v 是按照默认格式输出
   fmt.Printf("strAry %+v\n", strAry)
   fmt.Printf("sliceAry %+v\n", sliceAry)
   fmt.Printf("dic %+v\n", dic)
}

切片通过索引的方式指向了数组。切片是可以更改某个元素内容的,数组则不能,在开发中,主要都是使用切片来进行逻辑处理。

条件判断语句

Go 复制代码
package main

import "fmt"

func main() {
   // 可以通过 := 这种方式直接初始化基础变量
   localStr := "case3"

   if localStr == "case3" {
      fmt.Printf("into ture logic\n")
   } else {
      fmt.Printf("into false logic\n")
   }

   //字典初始化
   var dic = map[string]int{
      "apple":      1,
      "watermelon": 2,
   }

   // 用于检查字典中某个键是否存在,如果存在 num 取键值,ok 取 true,反之 ok 取 false
   if num, ok := dic["orange"]; ok {
      fmt.Printf("orange num %d\n", num)
   }
   if num, ok := dic["watermelon"]; ok {
      fmt.Printf("watermelon num %d\n", num)
   }

   switch localStr {
   case "case1":
      fmt.Println("case1")
   case "case2":
      fmt.Println("case2")
   case "case3":
      fmt.Println("case3")
   default:
      fmt.Println("default")
   }
}

循环

Go 复制代码
package main

import "fmt"

func main() {
   for i := 0; i < 5; i++ {
      fmt.Printf("i = %d ", i)
   }
   fmt.Println("")

   j := 0
   for {
      if j == 5 {
         break
      }
      fmt.Printf("j = %d ", j)
      j++
   }
   fmt.Println("")

   // 可以指定初始个数也
   var strAry = []string{"aa", "bb", "cc", "dd", "ee"}

   //切片初始化
   var sliceAry = make([]string, 0)
   sliceAry = strAry[1:3]

   for i, str := range sliceAry {
      fmt.Printf("slice i %d, str %s ", i, str)
   }
   fmt.Println("")

   //字典初始化
   var dic = map[string]int{
      "apple":      1,
      "watermelon": 2,
   }

   for k, v := range dic {
      fmt.Printf("key %s, value %d\n", k, v)
   }
}

range 关键字用于迭代切片、数组、字典等可迭代的数据结构。

协程

Go 复制代码
package main

import (
   "fmt"
   "time"
)

func a() {
   time.Sleep(3 * time.Second)
   fmt.Println("it's a")
}

func b() {
   time.Sleep(2 * time.Second)
   fmt.Println("it's b")
}

func c() {
   time.Sleep(1 * time.Second)
   fmt.Println("it's c")
}

func main() {
   go a()
   go b()
   go c()
   time.Sleep(5 * time.Second)
}

只要使用关键字 go 就能让 a,b,c 三个函数并发运行。

通道(channel)

通道的要点:

1.类似 Linux 中管道(pipe),先进先出; 2.线程安全,多个 goroutine 同时访问,不需要加锁; 3.channel 是有类型的,一个整数的 channel 只能存放整数。

通道的定义:

Go 复制代码
var ch0 chan int
var ch1 chan string
var ch2 chan map[string]string

type stu struct{}

var ch3 chan stu
var ch4 chan *stu

通道可以用于协程之间数据的传递,一般分为有缓冲通道无缓冲通道

两个协程间如果有数据交流,这时候就可以用通道来传递。

Go 复制代码
package main

import (
   "fmt"
   "time"
)

var ch chan int

func a() {
   time.Sleep(3 * time.Second)
   a := 5
   ch <- a // 发送操作
   fmt.Println("out of a")
}

func b() {
   time.Sleep(1 * time.Second)
   fromA := <-ch // 接收操作
   b := fromA + 3
   fmt.Println("b is ", b)
}

func main() {
   ch = make(chan int, 1)
   go a()
   go b()
   time.Sleep(20 * time.Second)
   fmt.Println("out of main")
}
  1. make(chan int, 1) 用于创建一个新的信道,其中 chan int 表示该信道用于传输整数类型的值。
  2. 逗号后的 1 是指定信道的缓冲大小。缓冲大小表示信道可以同时容纳的元素个数。 在这种情况下,ch 是一个缓冲大小为 1 的信道,即最多可以同时容纳一个整数值。

举个例子:

创建缓冲信道时,当发送操作(ch <- value)发生时,如果缓冲区已满,发送操作将被阻塞,直到有接收操作(value = <-ch)从缓冲区中读取值。类似地,当接收操作(value = <-ch)发生时,如果缓冲区为空,接收操作将被阻塞,直到有发送操作(ch <- value)将值放入缓冲区。

Go 复制代码
chSync := make(chan int)    // 无缓冲
chAsyn := make(chan int, 1) // 有缓冲

理解有缓冲和无缓冲:

同样是向通道里塞一个数据:chSync <-1 无缓冲场景 :一直要等有别的协程通过<-chSync接手了这个参数,那么chSync<-1才会继续下去,要不然就一直阻塞着。 有缓冲场景:chAsyn<-1则不会阻塞,因为缓冲大小是1,只有当放第二个值的时候,第一个还没被人拿走,这时候才会阻塞。 仔细理解下,实际这就是同步和异步的区别,无缓冲一定是同步等待,有缓冲只有在缓冲满了,异步又处理不过来的时候,才会阻塞。

举个例子:

无缓冲

Go 复制代码
package main

import (
   "fmt"
   "time"
)

var ch chan int

func a() {
   time.Sleep(3 * time.Second)
   a := 5
   ch <- a
   fmt.Println("out of a")
}

func b() {
   time.Sleep(1 * time.Second)
}

func main() {
   ch = make(chan int) // 无缓冲管道
   go a()
   go b()
   time.Sleep(20 * time.Second)
   fmt.Println("out of main")
}

输出:

Go 复制代码
out of main

有缓冲:

Go 复制代码
package main

import (
   "fmt"
   "time"
)

var ch chan int

func a() {
   time.Sleep(3 * time.Second)
   a := 5
   ch <- a
   fmt.Println("out of a")
}

func b() {
   time.Sleep(1 * time.Second)
}

func main() {
   ch = make(chan int, 1) // 有缓冲管道
   go a()
   go b()
   time.Sleep(20 * time.Second)
   fmt.Println("out of main")
}

输出:

Go 复制代码
out of a
out of main

接口

Go 复制代码
package main

import "fmt"

// Shape 是接口
type Shape interface {
   Area() float64
   Perimeter() float64
}

type Rect struct {
   height float64
   weight float64
}

func (p *Rect) Area() float64 {
   return p.height * p.weight
}

func (p *Rect) Perimeter() float64 {
   return 2 * (p.height + p.weight)
}

func main() {
   var s Shape = &Rect{height: 10, weight: 8}
   fmt.Println(s.Area())
   fmt.Println(s.Perimeter())
}

代码中Shape就是一个接口,声明了两个方法:面积(Area)和周长(Perimeter)。 咱们定义了一个具体结构 Rect,实现这个接口。可以看到,用基础的 Shape 接口,可以一个指向 Rect 对象,并调用其方法。

Golang 只需要实现某个 interface 的全部方法,那么就是实现了该类型。所以,Golang的继承关系是非侵入式的,这也是Golang的特色与优点。

webserver

用 http 裸写:

Go 复制代码
package main

import (
   "log"
   "net/http"
)

func SayHello(w http.ResponseWriter, r *http.Request) {
   w.Write([]byte("hello")) // 以字符串"hello"作为返回包
}

func main() {
   http.HandleFunc("/say_hello", SayHello)
   err := http.ListenAndServe(":8080", nil) // 开启一个http服务
   if err != nil {
      log.Print("ListenAndServe: ", err)
      return
   }
}

运行,然后就能访问了:http://localhost:8080/say_hello

写在最后:

以上就是本篇文章的内容了,感谢你的阅读。

如果感到有所收获的话可以给博主点一个赞哦。

如果文章内容有遗漏或者错误的地方欢迎私信博主或者在评论区指出~

相关推荐
湫ccc1 小时前
《Python基础》之字符串格式化输出
开发语言·python
mqiqe1 小时前
Python MySQL通过Binlog 获取变更记录 恢复数据
开发语言·python·mysql
AttackingLin1 小时前
2024强网杯--babyheap house of apple2解法
linux·开发语言·python
2401_857610032 小时前
SpringBoot社团管理:安全与维护
spring boot·后端·安全
Ysjt | 深2 小时前
C++多线程编程入门教程(优质版)
java·开发语言·jvm·c++
凌冰_2 小时前
IDEA2023 SpringBoot整合MyBatis(三)
spring boot·后端·mybatis
ephemerals__2 小时前
【c++丨STL】list模拟实现(附源码)
开发语言·c++·list
码农飞飞2 小时前
深入理解Rust的模式匹配
开发语言·后端·rust·模式匹配·解构·结构体和枚举