Go xmas2020 学习笔记 00-03、Basic Types

课程地址 go-class-slides/xmas-2020 at trunk · matt4biz/go-class-slides (github.com)

主讲老师 Matt Holiday

image-20220401081031592

00-02-Hello Example

目录结构

L:.
│   main.go
│
└───hello
        hello.go
        hello_test.go
  • main.go 是主程序入口
  • hello.go 是 hello 模块
  • hello_test.go 用于单元测试 hello 模块

不一样的Hello World

package hello

import (
	"strings"
)

func Say(names []string) string {
	if len(names) == 0 {
		names = []string{"world"}
	}

	return "Hello, " + strings.Join(names, ", ") + "!"
}

传入参数是一个字符串切片,当切片长度为 0 时,自动给定一个长度为 1 的切片。

然后调用 strings.Join 方法将字符串切片各个元素根据间隔符 合并,在进行 + 运算符后返回完整字符串。

巧妙的单元测试

hello_test.go

package hello

import "testing"

func TestSayHello(t *testing.T) {
	subtests := []struct {
		items  []string
		result string
	}{
		{
			result: "Hello, world!",
		},
		{
			items:  []string{"Matt"},
			result: "Hello, Matt!",
		},
		{
			items:  []string{"Matt", "Anne"},
			result: "Hello, Matt, Anne!",
		},
	}

	for _, st := range subtests {
		if s := Say(st.items); s != st.result {
			t.Errorf("wanted %s (%v) | got %s", st.result, st.items, s)
		}
	}

}

subtests 是一个匿名结构体的切片,我们可以在第二个花括号定义切片元素。

将参数与结果放在一起,for循环 subtests 进行多个单元测试,如果与预期不符就通过 t.Errorf 报错

因为 Say 方法在 Hello.go 中首字母大写声明,所以为 Public 公开,外界可用

传入os.Args切片

main.go

package main

import (
	"Work/Work/Study/Matt/2_cmd/hello"
	"fmt"
	"os"
)

func main() {
	fmt.Println("Hello,", hello.Say(os.Args[1:]))
}

导入了hello包,通过 包名.方法名 调用(可以给包名起别名),因为 Say 函数需要传入一个字符串切片,我们不能直接传入 os.Args[1] 否则是一个字符串变量,巧妙的是可以用切片截取 os.Args[1:] 的方式获取一整个切片。

os.Args[n] 通常是运行go程序时添加的多余参数,os.Args[0] 是程序的绝对路径。

go run main.go cat dog

os.Args[0] 输出 C:/xxx/xxx/xxx/main.go
os.Args[1] 输出 cat
os.Args[2] 输出 dog 

go mod init

go mod init hello

用于在当前根目录下生成 go.mod 文件,可以 ignore GOPATH,可用于在任何目录下的代码编写。go 会自动做处理。

03-Basic Types

变量类型与解释器

image-20220401054655735

先看右图,在 python 中,a并不是计算机实际意义上的数字,a是在解释器中表示或伪装的数字,使用C编写的解释器将使用底层硬件来做实际的数学运算,把这些东西编成二进制数字。所以在python中虽然a=2,但计算机并不能立刻知道。

来看左图,a纯粹是机器中内存位置的地址,没有解释器,没有jvm。这就是go的性能优势,go编译器直接生成机器代码,操作要快很多。

a:=2 在64位系统上,默认 64位 int

不要用内置浮点类型表示金钱

尝试使用内置浮点类型来表示金钱是一种不好的做法,几乎所有语言都是如此。浮点数实际上是为了科学计算。

使用内置浮点数表示金钱会有表示错误(精确度问题),缺少逻辑(100美分三次分割问题)

变量声明方式

image-20220401060131381

特殊类型

image-20220401061413369

go 中布尔值跟数字双方是独立的,不能互相转换和比较。

变量初始化

image-20220401061757414

如果不希望初始化最好使用 var 声明变量,如果需要初始化使用短声明语法

常量定义

image-20220401061846775

go 限制常量为 数字,字符串,布尔值 类型。

类型转换

package main

import "fmt"

func main() {
	a := 2
	b := 3.1
	fmt.Printf("a: %8T %v\n", a, a)
	fmt.Printf("b: %8T %[1]v\n", b) // ^ [1] 是Printf方法第二个参数

	a = int(b) // ^ go 是一门严格的语言,需要进行显式类型转换
	fmt.Printf("a: %8T %[1]v\n", a)
	b = float64(a)
	fmt.Printf("b: %8T %[1]v\n", b)
}

求平均值、标准流

package main

import (
	"fmt"
	"os"
)

func main() {
	var sum float64
	var n int
	for {
		var val float64
		if _, err := fmt.Fscanln(os.Stdin, &val); err != nil {
			fmt.Println(err)
			break
		} else {
			sum += val
			n++
		}
	}

	if n == 0 {
		fmt.Fprintln(os.Stderr, "no values") // ^ 需要告诉在哪个输出流上打印
		os.Exit(-1)
	}

	fmt.Println("The average is", sum/float64(n)) // ^ go没有自动转换,需要强制转换
}

_, err := fmt.Fscanln(os.Stdin, &val) 用于从标准输入流获取输入的行数据,并进行转换,转换失败会将错误返回给 err,否则 err 为 nil

fmt.Fprintln(os.Stderr, "no values")Println 差不多,只是需要告诉在哪个输出流上打印

posted @ 2022-04-01 08:13  小能日记  阅读(15)  评论(0编辑  收藏  举报