复习 Golang Chapter 2 原始类型和声明

发布时间 2023-11-05 17:32:54作者: 我听不见
  • 内建类型的使用
  • 变量与常量的使用以及惯例

写一些代码,看一看如何"最好"的运用他们,关于什么是“最好”,这里有一个最主要的原则:让你的意图能够透过代码清晰的表示出来

内建类型 Built-in Types
惯用法是跨语言使用者的障碍,学一门新的编程语言,主要是向这个方向靠拢(可通过开源代码和 ChatGPT 解决)

分配一个默认的 zero value 到所有已声明但未赋值变量是 Go 的特点

字面量 Literals

四种字面量:整型,浮点,字符,字符串

整型字面量的表示:

121 // 普通十进制数
0xAD // 十六进制
0o17 // 也可以 0 开头,但不建议
0b101 // 二进制
1_234 // 下划线无特殊作用,只是让 coder 读数字更轻松一些,千分位或者8bit 1,000,000 -> 1_000_000; 0xAA -> 0b1010_1010
1_2_3_4

浮点型字面量:

2.2e2 // 220 指数指定小写e 
2.2e-2 // 0.022 指数指定小写e 
0.321_33_2 // 0.321332 下划线无特殊作用,仅用作提升写代码人的可读性

字符 Rune

'a'
'\142'
'\x21'
'\u0022'
'\U00000001'
'\n'
'\t'
'\\'

字符串 String

"Hello World" // double quotes
`Hello "World"` // raw string literal

如果两个整型变量size不一致,是无法相加的
但是整型字面量可以用到浮点表达式当中,也可以分配一个整型字面量到浮点型变量中
因为字面量是 untyped 的,可以提高代码编写的灵活性,不对字面量作强制类型要求
如果分配的字面量超出了变量的类型上限,会引起编译时错误
在某些情况,没有在表达式中明确指定类型的字面量,会为字面量使用一个 default type

布尔 Booleans

var foobar bool // default `zero value` is `false`

数字 Numeric Types

Go 3 类 12 种

整型 Integer

类型 alias range
int8 -27~27-1
int16 -215~215-1
int32 rune, (uint, int if 32-bit CPU) -231~231-1
int64 (uint, int if 64-bit CPU) -263~263-1
uint8 byte 0~2^8-1
uint16 0~2^16-1
uint32 0~2^32-1
uint64 0~2^64-1

相比其他语言提供了丰富的整型类型

设计函数库的一种模式:
Go 标准库中有很多使用 int64 以及 uint64 编写的函数 ParseInt/ParseUint,用户在使用的时候自行转换类型即可,这样就不用为每一种类型分别编写函数,因为 Go 暂时不支持重载 generics

一个关于整型类型使用技巧是:不要过早优化,总是使用 int,除非被明显证明不可行
算术操作符
+ - * / %
+= -= *= /= %=
逻辑符号
== != > >= < <=
比特操作符
<< >> & | ^ &^
<<= >>= &= |= ^= &^=

浮点型 Float Number

类型 alias range
float32 -231~231-1
float64 -263~263-1
总是使用 float64,除非你必须去兼容一个已存在的格式
浮点字面量默认为 float64
float32 只有 6 或者 7 位表示小数
不要过早担心内存占用问题,除非你使用 profiler 检测出这是一个需要认真对待的决策
与其他语言一样,浮点数因为精确度问题不能用于做定点数做的工作,在涉及精确的金额问题的时候最好转换为定点数(浮点数多用于图形图像和科学计算)
浮点数的存储标准 IEEE_754
因为不精确 inexact 特性,不建议使用 == 或者 != 比较浮点数,给出一个区间然后用 > < 是比较好的做法

复数 Complex types

skip

字符与字符串

与 Java 不同,字符串是作为 Go 的内建类型而存在的,Go 的目的就是为了解决网络应用程序开发的效率问题,而整个网络中处理,传输最多的就是字符串。
字符串不可变,不可变的意思是只能被一整块的重新分配到内存,而不可以修改字符串在内存中的比特位
码点 code point,rune 是 int32 的别名

明确的类型转换

忘记掉自动类型转换规则

Go 不处理类型提升,必须由 coder 亲自转换类型后再处理,不同 size 的整型和浮点型也不行,必须明确的手动的进行类型转换
如果你使用多个编程语言协同工作,其实这是一个好事,不用记住每种编程语言的转换特点。

变量

var foo int = 10
var bar = 20
xyz := 30
var x int
var x,y int = 10, 20
var x, y, z float64 // zero value
var x, y = 22, "Hello World"
var (
	x int
	y float64
)

区别

var 可以在 package 级别使用,:= 只能在 function 作用域使用

使用技巧

初始化为 zero value 不需要使用 :=,直接使用 var就行,比如

x := 0 // ❌
var x int // ✔️

仅仅靠字面量不足以推导你想要的类型的时候使用 var

#include <stdio.h>

// 有的语言可以在字面量上追加修饰符来指明类型 `10L`, `20LL`, `10D`
int main() {
        printf("%ld", 10L);
        return 0;
}

但是 Go 中没有这种操作,所以可以使用 var 来解决字面量缺乏类型的问题

x := byte(20) // ❌
var x byte = 20 // ✔️

需要在代码上下文中明确区分新变量旧变量的时候使用 var(因为 := 具有隐式重新赋值的能力 reassign)

你不应该经常在包作用域 package scope 下声明变量并变动它的值,主要是基于调试跟踪困难来考虑,因为数据流穿梭于整个包作用域下,跟踪打断点比较麻烦。
包变量按常量方式使用是可接受的

常量 const

常量在 Go 中是一种给字面量起名字的方式,没有办法确保值完全不被修改
像 array,slices,maps,常量引用的只是一个地址,地址内的内容并不受控制

const x int = 10
const (
	a = 1
	b = "hello"
)
const foo = 60 * 60 * 24

func main() {
	const x = 10
}

常量类型的问题

const x = 100 // 这是一个无类型的常量

var y int = x // ✔️
var z float64 = x // ✔️
var d byte = x // ✔️

const y int = 100 // 这是一个有类型的常量
var g float64 = y // ❌

未使用的变量会被在编译时检查,每一个声明的 local 变量必须被至少取值过一次
常量没有限制,未被使用的常量不会出现在二进制文件中

变量命名的约定

字母与下划线数字都是可以的

idiomatic Go doesn’t use snake case

小驼峰是 Go 的惯用样式
下划线本身也是一个特别的标识符,通常用于函数返回值的 ignore 处理

Go 不使用大写字母下划线组合的常量,因为包级别的声明下,大写开头的变量函数可以被外部访问
函数内部偏好短变量名,作用域越小,变量名越短是一个惯例,单字母变量名是很常见的
函数外部 package level 变量名尽可能详尽一些,关于变量命名规则可以查看 关于代码风格的规范
Go 不在变量名中体现变量类型(匈牙利命名法)