Golang 下载
安装包链接:https://share.weiyun.com/InsZoHHu
IDE 下载:https://www.jetbrains.com/go/
第一个 golang 程序
package main
import "fmt"
func main() {
fmt.Println("hello golang")
}
每个可执行代码都必须包含 Package、import 以及 function 这三个要素。
变量
主函数文件:
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 包的文件:
package package1
import (
"fmt"
)
var Str string
func Fun() {
fmt.Println("test")
}
注意:golang是以首字母大小写来区分对包外是否可见。
所以 Fun() 函数,Str,想要在 main 文件被访问,都首字母大写了。
数组,切片,字典
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)
}
切片通过索引的方式指向了数组。切片是可以更改某个元素内容的,数组则不能,在开发中,主要都是使用切片来进行逻辑处理。
条件判断语句
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")
}
}
循环
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 关键字用于迭代切片、数组、字典等可迭代的数据结构。
协程
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 只能存放整数。
通道的定义:
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
通道可以用于协程之间数据的传递,一般分为有缓冲通道和无缓冲通道。
两个协程间如果有数据交流,这时候就可以用通道来传递。
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")
}
- make(chan int, 1) 用于创建一个新的信道,其中 chan int 表示该信道用于传输整数类型的值。
- 逗号后的 1 是指定信道的缓冲大小。缓冲大小表示信道可以同时容纳的元素个数。 在这种情况下,ch 是一个缓冲大小为 1 的信道,即最多可以同时容纳一个整数值。
举个例子:
创建缓冲信道时,当发送操作(ch <- value)发生时,如果缓冲区已满,发送操作将被阻塞,直到有接收操作(value = <-ch)从缓冲区中读取值。类似地,当接收操作(value = <-ch)发生时,如果缓冲区为空,接收操作将被阻塞,直到有发送操作(ch <- value)将值放入缓冲区。
chSync := make(chan int) // 无缓冲
chAsyn := make(chan int, 1) // 有缓冲
理解有缓冲和无缓冲:
同样是向通道里塞一个数据:chSync <-1 无缓冲场景:一直要等有别的协程通过<-chSync接手了这个参数,那么chSync<-1才会继续下去,要不然就一直阻塞着。 有缓冲场景:chAsyn<-1则不会阻塞,因为缓冲大小是1,只有当放第二个值的时候,第一个还没被人拿走,这时候才会阻塞。 仔细理解下,实际这就是同步和异步的区别,无缓冲一定是同步等待,有缓冲只有在缓冲满了,异步又处理不过来的时候,才会阻塞。
举个例子:
无缓冲:
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")
}
输出:
out of main
有缓冲:
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")
}
输出:
out of a
out of main
接口
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 裸写:
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
写在最后:
以上就是本篇文章的内容了,感谢你的阅读。
如果感到有所收获的话可以给博主点一个赞哦。
如果文章内容有遗漏或者错误的地方欢迎私信博主或者在评论区指出~
版权归原作者 戊子仲秋 所有, 如有侵权,请联系我们删除。