【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

写在最后:

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

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

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

相关推荐
萧鼎1 小时前
Python并发编程库:Asyncio的异步编程实战
开发语言·数据库·python·异步
学地理的小胖砸1 小时前
【一些关于Python的信息和帮助】
开发语言·python
疯一样的码农1 小时前
Python 继承、多态、封装、抽象
开发语言·python
^velpro^1 小时前
数据库连接池的创建
java·开发语言·数据库
秋の花1 小时前
【JAVA基础】Java集合基础
java·开发语言·windows
小松学前端1 小时前
第六章 7.0 LinkList
java·开发语言·网络
可峰科技1 小时前
斗破QT编程入门系列之二:认识Qt:编写一个HelloWorld程序(四星斗师)
开发语言·qt
customer081 小时前
【开源免费】基于SpringBoot+Vue.JS周边产品销售网站(JAVA毕业设计)
java·vue.js·spring boot·后端·spring cloud·java-ee·开源
全栈开发圈1 小时前
新书速览|Java网络爬虫精解与实践
java·开发语言·爬虫
面试鸭1 小时前
离谱!买个人信息买到网安公司头上???
java·开发语言·职场和发展