云原生:01_Golang_day1

模块一:Go语言特性

统一思想-12 factors

  • I. 基准代码
    一份基准代码,多份部署

  • II. 依赖
    显式声明依赖关系

  • III. 配置
    在环境中存储配置

  • IV. 后端服务
    把后端服务当作附加资源

  • V. 构建,发布,运行
    严格分离构建和运行

  • VI. 进程
    以一个或多个无状态进程运行应用

  • VII. 端口绑定
    通过端口绑定提供服务

  • VIII. 并发
    通过进程模型进行扩展

  • IX. 易处理
    快速启动和优雅终止可最大化健壮性

  • X. 开发环境与线上环境等价
    尽可能的保持开发,预发布,线上环境相同

  • XI. 日志
    把日志当作事件流

  • XII. 管理进程
    后台管理任务当作一次性进程运行

一,为什么需要另外一种语言

语言原则

  • Less is exponentially more
  • Do Less, Enable More

为什么需要Go语言

  • 其他编程语言的弊端。

  • Go语言是一个可以编译高效,支持高并发的,面向垃圾回收的全新语言。\

    特性:

    • 秒级完成大型程序的单节点编译。
    • 依赖管理清晰。
    • 不支持继承,程序员无需花费精力定义不同类型之间的关系。
    • 支持垃圾回收,支持并发执行,支持多线程通讯。
    • 对多核计算机支持友好。

Go 语言不支持的特性

  • 不支持函数重载和操作符重载。
  • 为了避免在 C/C++ 开发中的一些 Bug 和混乱,不支持隐式转换。
  • 支持接口抽象,不支持继承。
  • 不支持动态加载代码。
  • 不支持动态链接库。(所有依赖都可以打包在工程里
  • 通过 recover 和 panic 来替代异常机制。
  • 不支持断言。
  • 不支持静态变量 。

Go语言特性衍生来源

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LJOCrJhJ-1632742431659)(images/image-20210916201905110.png)]

二,GO语言环境搭建

1,下载安装

  • go安装安装文件

    https://golang.google.cn/dl/

  • 下载安装二级制文件

  • 重要环境配置

    • GOROOT:Go的安装路径
    • GOPATH: 项目路径
      • src:存放源代码
      • pkg:存放依赖包
      • bin:存放可执行文件
    • 其他变量
      • GOOS,GOARCH,GOPROXY
      • 国内建议设置 goproxy:export GOPROXY=https://goproxy.cn
  • 查看本机环境变量: go env

set GO111MODULE=
set GOARCH=amd64
set GOBIN=E:\f.Coding\Golang\bin
set GOCACHE=C:\Users\Administrator\AppData\Local\go-build
set GOENV=C:\Users\Administrator\AppData\Roaming\go\env
set GOEXE=.exe
set GOEXPERIMENT=
set GOFLAGS=
set GOHOSTARCH=amd64
set GOHOSTOS=windows
set GOINSECURE=
set GOMODCACHE=E:\f.Coding\Golang\pkg\mod
set GONOPROXY=
set GONOSUMDB=
set GOOS=windows
set GOPATH=E:\f.Coding\Golang
set GOPRIVATE=
set GOPROXY=https://goproxy.cn
set GOROOT=D:\Tools\Go
set GOSUMDB=sum.golang.org
set GOTMPDIR=
set GOTOOLDIR=D:\Tools\Go\pkg\tool\windows_amd64
set GOVCS=
set GOVERSION=go1.17
set GCCGO=gccgo
set AR=ar
set CC=gcc
set CXX=g++
set CGO_ENABLED=1
set GOMOD=NUL
set CGO_CFLAGS=-g -O2
set CGO_CPPFLAGS=
set CGO_CXXFLAGS=-g -O2
set CGO_FFLAGS=-g -O2
set CGO_LDFLAGS=-g -O2
set PKG_CONFIG=pkg-config
set GOGCCFLAGS=-m64 -mthreads -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=C:\Users\ADMINI~1\AppData\Local\Temp\go-build1871142733=/tmp/go-build -gno-record-gcc-switches

2,IDE设置(VS Code)

  • 下载安装vscode
  • 安装插件
  • 其他可选项
    • goland
    • vim,sublime

3,一些基本命令

命令 含义
install compile and install packages and dependencies (编译安装包)
list list packages or modules
mod module maintenance( 依赖管理)
run compile and run Go program
test test packages (做测试,单元测试)
tool run specified go tool (工具测试)
version print Go version
vet report likely mistakes in packages( 代码静态,编译器检查不出来的错误(不一定导致程序出错,写法错误))
get add dependencies to current module and install them(下载包到本地)

Go build

  • go build main.go 编译

    go build –o bin/mybinary .
    

    GOOS= linux go build mian.go

  • fmt 给你格式化,空格

    go fmt main.go  
    

Go test

(1) 示例

import "testing"
func TestIncrease(t *testing.T) {
    t.Log("Start testing")
    increase(1, 2)
}
  • go test ./… -v 运行测试
  • go test命令扫描所有*_test.go为结尾的文件,惯例是将测试代码与正式代码放在同目录,
  • 如 foo.go 的测试代码一般写在 foo_test.go .

Go vet

代码静态检查,发现可能的 bug 或者可疑的构造

  • Print-format 错误,检查类型不匹配的print
str := “hello world!// str类型是字符串,格式化输出的时候应该用s%,这里用的d%
fmt.Printf("%d\n", str)
  • Boolean 错误,检查一直为 true、false 或者冗余的表达式
// 
fmt.Println(i != 0 || i != 1)
  • Range 循环,比如如下代码主协程会先退出,go routine无法被执行
    Unreachable的代码,如 return 之后的代码
//
words := []string{"foo", "bar", "baz"}
for _, word := range words {
	go func() {
		fmt.Println(word).
	}()
}
  • 其他错误,比如变量自赋值,error 检查滞后等
res, err := http.Get("https://www.spreadsheetdb.io/")
defer res.Body.Close()
if err != nil {
	log.Fatal(err)
}

(1) 示例

package main

import (
	"fmt"
)

func main() {
	name := "testing"
	fmt.Printf("%d\n", name)
	fmt.Printf("%s\n", name, name)
}
PS E:\f.Coding\Golang\src\github.com\cncamp\golang\examples\module1\govet> go vet main.go
# command-line-arguments
.\main.go:9:2: Printf format %d has arg name of wrong type string
.\main.go:10:2: Printf call needs 1 arg but has 2 args

4,代码管理管理

  • 下载并安装 Git Command Line
    https://git-scm.com/downloads

  • Github

    • 本课程示例代码均上传在 https://github.com/cncamp/golang
    • 创建代码目录
    mkdir –p $GOPATH/src/github.com/cncamp
    cd $GOPATH/src/github.com/cncamp
    
  • 代码下载

    git clone https://github.com/cncamp/golang.git
    
  • 修改代码

  • 上传代码

    git add filename
    git commit –m 'change logs'
    git push  
    

5,Golang playground

  • 官方 playground
    https://play.golang.org/
    可直接编写和运行 Go 语言程序

  • 国内可直接访问的 playground
    https://goplay.tool

  • go指南

    https://tour.go-zh.org/

三,控制结构

1,if 表达式

  • 基本形式
if condition1 {
// do something
} else if condition2 {
// do something else
} else {
// catch-all or default
}
  • 简短形式
    • 同 for 一样, if 语句可以在条件表达式前执行一个简单的语句。
if v:=x-100; v<0{
	return v
}

实例一:基本形式

package main

import (
	"fmt"
	"math"
)

func sqrt(x float64) string {
	if x < 0 {
		return sqrt(-x) + "i"
	}
	return fmt.Sprint(math.Sqrt(x))
}

func main() {
	fmt.Println(sqrt(2), sqrt(-4))
}

示例二:简短形式

package main

import (
	"fmt"
	"math"
)

func pow(x, n, lim float64) float64 {
	if v := math.Pow(x, n); v < lim {
		return v
	}
	return lim
}

func main() {
	fmt.Println(
		pow(3, 2, 10),
		pow(3, 3, 20),
	)
}

2,switch:

分支很多的情况,if的多条件

switch var1 {
case val1: //空分支
case val2:
	fallthrough //执行case3中的f() 
case val3:
	f()	
default: //默认分支
...

示例

package main

import (
	"fmt"
	"time"
)

func main() {
	fmt.Println("When's Saturday?")
	today := time.Now().Weekday()
	switch time.Saturday {
	case today + 0:
		fmt.Println("Today.")
	case today + 1:
		fmt.Println("Tomorrow.")
	case today + 2:
		fmt.Println("In two days.")
	default:
		fmt.Println("Too far away.")
	}
}

特别注意

1,golang中switch每个case中默认自带break,执行完后就退出了,不会执行下面条件。

2,fallthrouth意思是不退出继续执行下面的语句。

3,for 循环

go 语言只有一种循环:for循环

  • 计入计数器循环
    • for 初始化语句; 条件语句; 修饰语句 {}
for i:=0; i<10;i++{
	sum+=i
}
  • 初始化语句和后置可选,此场景与while等价(go语言不支持while)
for ; sum < 1000; {
	sum += sum
}
  • 无限循环
for {
    if condition1 {
    	break
    }
}

示例

package main

import (
	"fmt"
)

func main() {
	for i := 0; i < 3; i++ {
		fmt.Println(i)
	}
	fullString := "hello world"
	fmt.Println(fullString)
	for i, c := range fullString {
		fmt.Println(i, string(c))//循环打印下标和字符串
	}
}

4,for-range

  • 遍历数组切片字符串,MAP等
for index, char := range myString {
...
}
for key, value := range MyMap {
...
}
for index, value := range MyArray {
...
}

需要注意:如果 for range 遍历指针数组,则 value 取出的指
针地址为原指针地址的拷贝

示例

package main

import "fmt"

var pow = []int{1, 2, 4, 8, 16, 32, 64, 128}

func main() {
	for i, v := range pow {
		fmt.Printf("2**%d = %d\n", i, v)
	}
}

四、常用数据结构

1,变量和常量定义

  • 变量
    var 语句用于声明一个变量列表,跟函数的参数列表一样,类型在最后。

     var c, python, java bool
    
  • 变量的初始化
    • 变量声明可以包含初始值,每个变量对应一个。
    • 如果初始化值已存在,则可以省略类型;变量会从初始值中获得类型。

     var i, j int = 1, 2
    
  • 短变量声明
    • 在函数中,简洁赋值语句 := 可在类型明确的地方代替 var 声明。
    • 函数外的每个语句都必须以关键字开始(var, func 等等),因此 := 结构不能在函数外使用

     c, python, java := true, false, "no!"  
    

2,类型转换和推导

  • 类型转换
    表达式 T(v) 将值 v 转换为类型 T。

    • 一些关于数值的转换:
    var i int = 42
    var f float64 = float64(i)
    var u uint = uint(f)
    
    • 或者,更加简单的形式:
    i := 42
    f := float64(i)
    u := uint(f)
    
  • 类型推导
    在声明一个变量而不指定其类型时(即使用不带类型的 := 语法或 var = 表达式语法),变量的类型由右值推导得出。

    var i int
    j := i // j 也是一个 int  
    

3,数组

**定义:**相同类型且长度固定连续内存片段

  • 以编号访问每个元素

  • 定义方法

    var identifier [len]type
    
  • 示例

    yArray := [3]int{1,2,3}  
    

4,slice切片

**定义:**切片是对数组一个连续片段的引用

  • 数组定义中不指定长度即为切片

    var identifier []type
    
  • 切片在未初始化之前默认为nil, 长度为0

  • 常用方法

func main() {
    myArray := [5]int{1, 2, 3, 4, 5}
    mySlice := myArray[1:3]
    fmt.Printf("mySlice %+v\n", mySlice)
    fullSlice := myArray[:]
    remove3rdItem := deleteItem(fullSlice, 2)
    fmt.Printf("remove3rdItem %+v\n",
    remove3rdItem)
}
func deleteItem(slice []int, index int) []int {
    return append(slice[:index], slice[index+1:]...)
}

Make 和 New

  • New 返回指针地址

  • Make 返回第一个元素,可预设内存空间,避免未来的内存拷贝

  • 示例

    package main
    
    import (
    	"fmt"
    )
    
    func main() {
    	mySlice1 := new([]int)
    	mySlice2 := make([]int, 0)
    	mySlice3 := make([]int, 10)
    	mySlice4 := make([]int, 10, 20)
    	fmt.Printf("mySlice1 %+v\n", mySlice1)
    	fmt.Printf("mySlice2 %+v\n", mySlice2)
    	fmt.Printf("mySlice3 %+v\n", mySlice3)
    	fmt.Printf("mySlice4 %+v\n", mySlice4)
    }
    

关于切片的常见问题

  • 切片是连续内存并且可以动态扩展,由此引发的问题?

    a := []int{}
    b := []int{1,2,3}
    c := a
    a = append(b, 1)
    
  • 修改切片的值?

    mySlice := []int{10, 20, 30, 40, 50}
    for _, value := range mySlice {
    	value *= 2
    }
    fmt.Printf("mySlice %+v\n", mySlice)
    for index, _ := range mySlice {
    	mySlice[index] *= 2
    }
    fmt.Printf("mySlice %+v\n", mySlice)  
    

5,Map

定义声明

  • 声明方法

    var map1 map[keytype]valuetype
    
  • 示例

    myMap := make(map[string]string, 10)
    myMap["a"] = "b"
    myFuncMap := map[string]func() int{
    	"funcA": func() int { return 1 },
    }
    fmt.Println(myFuncMap)
    f := myFuncMap["funcA"]
    fmt.Println(f())  
    

访问 Map 元素

  • 按 Key 取值

    value, exists := myMap["a"]
    if exists {
    	println(value)
    }
    
  • 遍历 Map

    for k, v := range myMap {
    	println(k, v)
    }
    

6,结构体和指针

定义方式

  • 通过 type … struct 关键字自定义结构体

  • Go 语言支持指针,但不支持指针运算

  • 指针变量的值为内存地址

  • 未赋值的指针为 nil(不存在)

    type MyType struct {
    	Name string
    }
    func printMyType(t *MyType){
    	println(t.Name)
    }
    func main(){
    	t := MyType{Name: "test"}
    	printMyType(&t)
    }
    

7,结构体标签

  • 结构体中的字段除了有名字和类型外,还可以有一个可选的标签(tag)
  • 使用场景:Kubernetes APIServer 对所有资源的定义都用 Json tag 和 protoBuff tag
  • NodeName string json:"nodeName,omitempty" protobuf:"bytes,10,opt,name=nodeName"
type MyType struct {
	Name string `json:"name"`
}
func main() {
    mt := MyType{Name: "test"}
    myType := reflect.TypeOf(mt)
    name := myType.Field(0)
    tag := name.Tag.Get("json")
    println(tag)
}

8,类型别名

// Service Type string describes ingress methods for a service
type ServiceType string
const (
    // ServiceTypeClusterIP means a service will only be accessible inside the
    // cluster, via the ClusterIP.
    ServiceTypeClusterIP ServiceType = "ClusterIP"
    // ServiceTypeNodePort means a service will be exposed on one port of
    // every node, in addition to 'ClusterIP' type.
    ServiceTypeNodePort ServiceType = "NodePort"
    // ServiceTypeLoadBalancer means a service will be exposed via an
    // external load balancer (if the cloud provider supports it), in addition
    // to 'NodePort' type.
    ServiceTypeLoadBalancer ServiceType = "LoadBalancer"
    // ServiceTypeExternalName means a service consists of only a reference to
    // an external name that kubedns or equivalent will return as a CNAME
    // record, with no exposing or proxying of any pods involved.
    ServiceTypeExternalName ServiceType = "ExternalName"
)

本节练习

课后练习 1.1

  • 安装 Go

  • 安装 IDE 并安装 Go 语言插件

  • 编写一个小程序

    给定一个字符串数组
    ["I","am","stupid","and","weak"]
    用 for 循环遍历该数组并修改为
    ["I","am","smart","and","strong"]  
    
  • 解答

package main

import (
   "fmt"
)
func main()  {
   mylist :=[5]string{"I","am","stupid","and","weak"}
   fmt.Println(mylist)
   for i, v := range mylist{
      //fmt.Println(i, v)
      switch v {
      case "stupid":
         mylist[i]="smart"
      case "weak":
         mylist[i]="strong"
      default:
         break
      }
   }
   fmt.Println(mylist)
}

你可能感兴趣的:(Cncamp,golang,kubernetes)