在 Go 编程语言中,数据类型用于声明函数和变量
- 数据类型的出现是为了把数据分成所需内存大小不同的数据,编程的时候需要用大数据的时候才需要申请大内存,就可以充分利用内存
- Go 语言按类别有以下几种数据类型:
类型 | 描述 | |
---|---|---|
布尔型 | bool | 布尔型的值只可以是常量 true 或者 false 一个简单的例子:var b bool = true |
数字类型 | uintptr | 无符号整型,用于存放一个指针 |
byte | 类似 uint8 | |
int | 32 或 64 位 | |
rune | 类似 int32 | |
uint | 32 或 64 位 | |
整型 | uint8 无符号 8 位整型 (0 到 255) uint16 无符号 16 位整型 (0 到 65535) uint32 无符号 32 位整型 (0 到 4294967295) uint64 无符号 64 位整型 (0 到 18446744073709551615) int8 有符号 8 位整型 (-128 到 127) int16 有符号 16 位整型 (-32768 到 32767) int32 有符号 32 位整型 (-2147483648 到 2147483647) int64 有符号 64 位整型 (-9223372036854775808 到 9223372036854775807) |
|
浮点型 | float32 IEEE-754 32位浮点型数 float64 IEEE-754 64位浮点型数 |
|
复数 | complex64 32 位实数和虚数 complex128 64 位实数和虚数 |
|
字符串类型 | string | 字符串就是一串固定长度的字符连接起来的字符序列。Go 的字符串是由单个字节连接起来的。Go 语言的字符串的字节使用 UTF-8 编码标识 Unicode 文本 |
派生类型 | (a) 指针类型(Pointer) (b) 数组类型 (c) 结构化类型(struct) (d) Channel 类型 (e) 函数类型 (f) 切片类型 (g) 接口类型(interface) (h) Map 类型 |
bool
bool 类型表示一个布尔值,值为 true 或者 false
package main
import (
"fmt"
"unsafe"
)
func main() {
a := true
b := false
fmt.Println("a:", a, "b:", b)
c := a && b
fmt.Println("c:", c)
d := a || b
fmt.Println("d:", d)
fmt.Println("unsafe.Sizeof(d) =", unsafe.Sizeof(d))
}
在上面的程序中,a 赋值为 true,b 赋值为 false。
c 赋值为 a && b。仅当 a 和 b 都为 true 时,操作符 && 才返回 true。因此,在这里 c 为 false。
当 a 或者 b 为 true 时,操作符 || 返回 true。在这里,由于 a 为 true,因此 d 也为 true。我们将得到程序的输出如下
a: true b: false
c: false
d: true
unsafe.Sizeof(d) = 1
⚠️ 为了得到某类型或某变量在特定平台上的准确大小,可以使用 unsafe.Sizeof(type)获取对象或类型的存储字节大小
int
根据不同的底层平台(Underlying Platform),表示 32 或 64 位整型。除非对整型的大小有特定的需求,否则通常应该使用 int 表示整型
大小 在32位系统下是32位,而在64位系统下是64位
范围 在 32 位系统下是 -2147483648~2147483647,而在 64 位系统是 -9223372036854775808~9223372036854775807
package main
import "fmt"
func main() {
var a int = 89
b := 95
fmt.Println("value of a is", a, "and b is", b)
}
在 Printf 方法中,使用 %T 格式说明符(Format Specifier),可以打印出变量的类型。Go 的 unsafe 包提供了一个 Sizeof 函数,该函数接收变量并返回它的字节大小。unsafe 包应该小心使用,因为使用 unsafe 包可能会带来可移植性问题。不过出于本教程的目的,我们是可以使用的。
下面程序会输出变量 a 和 b 的类型和大小。格式说明符 %T 用于打印类型,而 %d 用于打印字节大小。
package main
import (
"fmt"
"unsafe"
)
func main() {
var a int = 89
b := 95
fmt.Println("value of a is", a, "and b is", b)
fmt.Printf("type of a is %T, size of a is %d", a, unsafe.Sizeof(a)) // a 的类型和大小
fmt.Printf("\ntype of b is %T, size of b is %d", b, unsafe.Sizeof(b)) // b 的类型和大小
}
以上代码运行输出:
[Running] go run "/Users/Ken/Desktop/test/main.go"
value of a is 89 and b is 95
type of a is int, size of a is 8
type of b is int, size of b is 8
[Done] exited with code=0 in 0.804 seconds
从上面的输出,我们可以推断出 a 和 b 为 int 类型,且大小都是 64 位(8 字节)。如果在 32 位系统下,a 和 b 会占用 32 位(4 字节)的大小
浮点型
float32:32 位浮点数
float64:64 位浮点数
package main
import ( "fmt"
)
func main() {
var c float32
a, b, c:= 5.67, 8.97, 1.1
fmt.Printf("type of a %T b %T c %T\n", a, b, c)
sum := a + b
diff := a - b
fmt.Println("sum", sum, "diff", diff)
no1, no2 := 56, 89
fmt.Println("sum", no1+no2, "diff", no1-no2)
}
a 和 b 的类型根据赋值推断得出。在这里,a 和 b 的类型为 float64(float64 是浮点数的默认类型)。我们把 a 和 b 的和赋值给变量 sum,把 b 和 a 的差赋值给 diff,接下来打印 sum 和 diff。no1 和 no2 也进行了相同的计算。上述程序将会输出:
[Running] go run "/Users/Ken/Desktop/test/main.go"
type of a float64 b float64 c float32
sum 14.64 diff -3.3000000000000007
sum 145 diff -33
[Done] exited with code=0 in 0.338 seconds
复数类型
complex64 实部和虚部都是 float32 类型的的复数
complex128 实部和虚部都是 float64 类型的的复数
内建函数 complex
用于创建一个包含实部和虚部的复数。complex 函数的定义如下:
func complex(r, i FloatType) ComplexType
该函数的参数分别是实部和虚部,并返回一个复数类型。实部和虚部应该是相同类型,也就是 float32 或 float64
- 如果实部和虚部都是 float32 类型,则函数会返回一个 complex64 类型的复数
- 如果实部和虚部都是 float64 类型,则函数会返回一个 complex128 类型的复数
简短语法来创建复数
c := 6 + 7i
下面我们编写一个简单的程序来理解复数:
package main
import (
"fmt"
)
func main() {
c1 := complex(5, 7)
c2 := 8 + 27i
cadd := c1 + c2
fmt.Println("sum:", cadd)
cmul := c1 * c2
fmt.Println("product:", cmul)
}
在上面的程序里,c1 和 c2 是两个复数。c1的实部为 5,虚部为 7。c2 的实部为8,虚部为 27。c1 和 c2 的和赋值给 cadd ,而 c1 和 c2 的乘积赋值给 cmul。该程序将输出:
sum: (13+34i)
product: (-149+191i)
- 加法法则
- 复数的加法按照以下规定的法则进行:设c1=a+bi,c2=c+di是任意两个复zhi数
- 则它们的和是 (a+bi)+(c+di)=(a+c)+(b+d)i
- 两个复数的和依然是复数,它的实部是原来两个复数实部的和,它的虚部是原来两个虚部的和
- 减法法则
- 复数的减法按照以下规定的法则进行:设c1=a+bi,c2=c+di是任意两个复数
- 则它们的差是 (a+bi)-(c+di)=(a-c)+(b-d)i
- 两个复数的差依然是复数,它的实部是原来两个复数实部的差,它的虚部是原来两个虚部的差
- 乘法法则
- 设c1=a+bi,c2=c+di(a、b、c、d∈R)是任意两个复数
- 那么它们的积(a+bi)(c+di)=(ac-bd)+(bc+ad)i
- 其实就是把两个复数相乘,类似两个多项式相乘,展开得: ac+adi+bci+bdi2,因为i2=-1,所以结果是(ac-bd)+(bc+ad)i 。两个复数的积仍然是一个复数
- 除法法则
- 复数除法定义:满足(c+di)(x+yi)=(a+bi)的复数x+yi(x,y∈R)叫复数a+bi除以复数c+di的商。
- 运算方法:可以把除法换算成乘法做,在分子分母同时乘上分母的共轭.。所谓共轭你可以理解为加减号的变换,互为共轭的两个复数相乘是个实常数
string 类型
在 Golang 中,字符串是字节的集合。如果你现在还不理解这个定义,也没有关系。我们可以暂且认为一个字符串就是由很多字符组成的。我们后面会在一个教程中深入学习字符串。
下面编写一个使用字符串的程序
package main
import (
"fmt"
)
func main() {
first := "Naveen"
last := "Ramanathan"
name := first +" "+ last
fmt.Println("My name is",name)
}
/* 上面程序中,first 赋值为字符串 “Naveen”
last 赋值为字符串 “Ramanathan”。+ 操作符可以用于拼接字符串
我们拼接了 first、空格和 last,并将其赋值给 name
上述程序将打印输出 My name is Naveen Ramanathan */
类型转换
Go 语言类型转换基本格式
type_name(expression)
type_name 为类型,expression 为表达式
整型转化为浮点型的示例
以下实例中将整型转化为浮点型,并计算结果,将结果赋值给浮点型变量:
package main
import "fmt"
func main() {
var sum int = 17
var count int = 5
var mean float32
mean = float32(sum)/float32(count)
fmt.Printf("mean 的值为: %.2f\n",mean)
}
/*
以上实例执行输出结果为:
mean 的值为: 3.40
*/
Go 有着非常严格的强类型特征。Go 没有自动类型提升或类型转换。我们通过一个例子说明这意味着什么
package main
import (
"fmt"
)
func main() {
i := 55 //int
j := 67.8 //float64
sum := i + j //invalid operation: i + j (mismatched types int and float64)
fmt.Println(sum)
}
/* 上面的代码在 C 语言中是完全合法的,然而在 Go 中,却是行不通的。
i 的类型是 int ,而 j 的类型是 float64 ,
我们正试图把两个不同类型的数相加,Go 不允许这样的操作。
如果运行程序,你会得到invalid operation: i + j (mismatched types int and float64) */
要修复这个错误,i 和 j 应该是相同的类型。在这里,我们把 j 转换为 int 类型。把 v 转换为 T 类型的语法是 T(v)
package main
import (
"fmt"
)
func main() {
i := 55 //int
j := 67.8 //float64
sum := i + int(j)
fmt.Println(sum)
}
现在,当你运行上面的程序时,会看见输出 122
赋值的情况也是如此。把一个变量赋值给另一个不同类型的变量,需要显式的类型转换
package main
import (
"fmt"
)
func main() {
i := 10
var j float64 = float64(i) // 若没有显式转换,该语句会报错
fmt.Println("j", j)
}
/* 在第8行,i 转换为 float64 类型,接下来赋值给 j。
如果不进行类型转换,当你试图把 i 赋值给 j 时,编译器会抛出错误。 */
GO输出打印的格式
GO语言中的格式说明符
printf() 函数的输出格式(Format Specifier)
类型 | 格式 | 描述 | 示例 |
---|---|---|---|
General | %v | 以默认的方式打印变量的值 | |
%T | 打印变量的类型 | ||
Integer | %+d | 带符号的整型 | fmt.Printf(“%+d”, 255) +255 |
%q | 打印单引号 | ||
%o | 不带零的八进制 | ||
%#o | 带零的八进制 | ||
%x | 小写的十六进制 | ||
%X | 大写的十六进制 | ||
%#x | 带0x的十六进制 | ||
%U | 打印Unicode字符 | ||
%#U | 打印带字符的Unicode | ||
%b | 打印整型的二进制 | ||
Integer width |
%d | 以十进制形式输出数据 | |
%ld | 表示按十进制长整型输出 | ||
%5d | 表示该整型最大长度是5,下面这段代码 | fmt.Printf(“|%5d|”, 1) fmt.Printf(“|%5d|”, 1234567) 输出结果如下: | 1| |1234567| |
|
%-5d | 则相反,打印结果会自动左对齐 | ||
%05d | 会在数字前面补零 | ||
Float | %f | 以浮点型形式输出数据,默认保留小数点后6位; | %.3f 最多3位小数来表示 %.6f 表示显示6位小数点 |
%e | 小数点( 科学计数法 ) |
%.6e 表示6位小数点 | |
%g | 用最少的数字来表示 | ||
%.3g | 最多3位数字来表示 | ||
%c | 以字符形式输出数据 | ||
String | %s | 正常输出字符串 | |
%q | 字符串带双引号,字符串中的引号带转义符 | ||
%#q | 字符串带反引号,如果字符串内有反引号,就用双引号代替 | ||
%o | 以八进制形式输出数据 | ||
%x | 将字符串转换为小写的16进制格式 | ||
%X | 将字符串转换为大写的16进制格式 | ||
/% x | 带空格的16进制格式 | ||
%s | 以字符串形式输出数据 | ||
String Width (以5做例子) |
%5s | 最小宽度为5 | |
%-5s | 最小宽度为5(左对齐) | ||
%.5s | 最大宽度为5 | ||
%5.7s | 最小宽度为5,最大宽度为7 | ||
%-5.7s | 最小宽度为5,最大宽度为7(左对齐) | ||
%5.3s | 如果宽度大于3,则截断 | ||
%05s | 如果宽度小于5,就会在字符串前面补零 | ||
Struct | %v | 正常打印 | {sam {12345 67890}} |
%+v | 带字段名称 | {name:sam phone:{mobile:12345 office:67890} | |
%#v | 用Go的语法打印 | 比如main.People{name:”sam”, phone:main.Phone{mobile:”12345”, office:”67890”}} | |
Boolean | %t | 打印true或false | |
Pointer | %p | 以 带0x的指针 地址形式输出数据 |
|
%#p | 不带0x的指针 地址形式输出数据 |
Go 进度条功能实现
package main
import(
"fmt"
"time"
)
type Bar struct {
percent int64 //百分比
cur int64 //当前进度位置
total int64 //总进度
rate string //进度条
graph string //显示符号
}
func (bar *Bar) NewOption(start, total int64) {
bar.cur = start
bar.total = total
if bar.graph == "" {
bar.graph = "█"
}
bar.percent = bar.getPercent()
for i := 0; i < int(bar.percent); i += 2 {
bar.rate += bar.graph //初始化进度条位置
}
}
func (bar *Bar) NewOptionWithGraph(start, total int64, graph string) {
bar.graph = graph
bar.NewOption(start, total)
}
func (bar *Bar) getPercent() int64 {
return int64(float32(bar.cur) / float32(bar.total) * 100)
}
func (bar *Bar) Play(cur int64) {
bar.cur = cur
last := bar.percent
bar.percent = bar.getPercent()
if bar.percent != last && bar.percent%2 == 0 {
bar.rate += bar.graph
}
fmt.Printf("\r[%-50s]%3d%% %8d/%d", bar.rate, bar.percent, bar.cur, bar.total)
}
func (bar *Bar) Finish(){
fmt.Println()
}
func main() {
var bar Bar
// bar.NewOption(0, 100)
bar.NewOptionWithGraph(0, 100, "#")
for i:= 0; i<=100; i++{
time.Sleep(100*time.Millisecond)
bar.Play(int64(i))
}
bar.Finish()
}
python语言中的格式说明符
1. 字符串格式代码
符号 | 说明 |
---|---|
%s | 字符串 |
%c | 字符 |
%d | 十进制(整数) |
%i | 整数 |
%u | 无符号整数 |
%o | 八进制整数 |
%x | 十六进制整数 |
%X | 十六进制整数大写 |
%e | 浮点数格式1 |
%E | 浮点数格式2 |
%f | 浮点数格式3 |
%g | 浮点数格式4 |
%G | 浮点数格式5 |
%% | 文字% |
2. 常用转义字符
转义符号 | 描述 |
---|---|
\(在尾行时) | 续行符 |
\\ | 反斜杠符号 |
\’ | 单引号 |
\” | 双引号 |
\a | 响铃 |
\b | 退格(Backspace) |
\e | 转义 |
\000 | 空 |
\n | 换行 |
\v | 纵向制表符 |
\t | 横向制表符 |
\r | 回车 |
\f | 换页 |
\oyy | 八进制数yy代表的字符 例如:\o12 代表换行 |
\xyy | 十进制数yy代表的字符 例如:\x0a12 代表换行 |
\other | 其他的字符以普通格式输出 |