package main

import "fmt"

// Go语言的数值类型包括几种不同大小的整数、浮点数和复数。
// 每种数值类型都决定了对应的大小范围和是否支持正负符号。

// Go语言同时提供了有符号和无符号类型的整数运算。
// 这里有int8、int16、int32和int64四种截然不同大小的有符号整数类型，
// 分别对应8、16、32、64bit大小的有符号整数，
// 与此对应的是uint8、uint16、uint32和uint64四种无符号整数类型。

// 其中 byte类型 与 int8类型 完全等价 其取值范围为[-128,127]
// 其中 rune类型 与 int32类型 完全等价 其取值范围为[-2147483648, 2147483647]

// uintptr 是一个无符号整型，其大小可以足够存放指针地址，一般用于指针运算，与其他语言混编时使用

// int 类型的大小一般与操作系统的架构、编译器有关。
// 不同的编译器即使在相同的硬件平台上可能产生不同的大小。
// 但其的大小一般为32或64位。注意其和 int32/int64 并不是同一类型

func main() {
	// 运算符
	// 下面的运算符优先级排序为逐级递减，同一级运算符使用从左向右的原则

	// *      /      %      <<       >>     &       &^
	// +      -      |      ^
	// ==     !=     <      <=       >      >=
	// &&
	// ||

	// 算术运算符+、-、*和/可以适用于整数、浮点数和复数，
	// 2但是取模运算符%仅用于整数间的运算。对于不同编程语言，%取模运算的行为可能并不相同。
	// 在Go语言中，%取模运算符的符号和被取模数的符号总是一致的，因此-5%3和-5%-3结果都是-2。
	fmt.Println(-5%3, -5%-3) // -2 -2
	// 除法运算符/的行为则依赖于操作数是否全为整数，
	// 比如5.0/4.0的结果是1.25，但是5/4的结果是1，因为整数除法会向着0方向截断余数。
	fmt.Println(5.0/4.0, 5/4, 5.0/4, 5/4.0) // 1.25 1 1.25 1.25
	// 可以看到操作数任意一个为浮点数，最后的结果也为浮点数

	// 一个算术运算的结果，不管是有符号或者是无符号的，如果需要更多的bit位才能正确表示的话，
	// 就说明计算结果是溢出了。超出的高位的bit位部分将被丢弃。
	// 如果原始的数值是有符号类型，而且最左边的bit位是1的话，那么最终结果可能是负的
	var byte1 byte = 127
	var ubyte1 uint8 = 255
	fmt.Println(byte1, byte1+1, byte1*byte1)     // 127 -128(溢出) 1(溢出)
	fmt.Println(ubyte1, ubyte1+1, ubyte1*ubyte1) // 255 0(溢出） 1(溢出)

	// 两个相同的整数类型可以使用下面的二元比较运算符进行比较；比较表达式的结果是布尔类型。
	// ==    等于
	// !=    不等于
	// <     小于
	// <=    小于等于
	// >     大于
	// >=    大于等于

	// 布尔型、数字类型和字符串等基本类型都是可比较的，
	// 也就是说两个相同类型的值可以用==和!=进行比较。
	fmt.Println(1 == 1) // true
	var number int = 123
	var bool1 bool = number == 100+23
	fmt.Println(bool1) //true
	// 此外，整数、浮点数和字符串可以根据比较结果排序。
	// 许多其它类型的值可能是不可比较的，因此也就可能是不可排序的。
	//fmt.Println("www" == 112)
	// 编译错误，invalid operation:
	// "www" == 112 (mismatched types untyped string and untyped int)
	// 所以 对于我们遇到的每种类型，我们需要保证规则的一致性。

	// 任何大小的整数字面值都可以用以0开始的八进制格式书写，例如0666；
	// 或用以0x或0X开头的十六进制格式书写，例如0xdeadbeef。
	o := 0666
	// [1] 表示访问格式化后的第一个操作数
	// %后的#副词表示告诉Printf在用%o、%x或%X输出时生成0、0x或0X前缀。
	fmt.Printf("%d %[1]o %#[1]o\n", o) // "438 666 0666"
	// 十六进制数字可以用大写或小写字母。
	x := int64(0xdeadbeef)
	fmt.Printf("%d %[1]x %#[1]x %#[1]X\n", x)
	// 3735928559 deadbeef 0xdeadbeef 0XDEADBEEF
	// 如今八进制数据通常用于POSIX操作系统上的文件访问权限标志，
	// 十六进制数字则更强调数字值的bit位模式。

	// 字符面值通过一对单引号直接包含对应字符。
	// 最简单的例子是ASCII中类似'a'写法的字符面值，
	// 但是我们也可以通过转义的数值来表示任意的Unicode码点对应的字符，马上将会看到这样的例子。

	// 字符使用%c参数打印，或者是用%q参数打印带单引号的字符：
	ascii := 'a'
	unicode := '国'
	newline := '\n'
	fmt.Printf("%d %[1]c %[1]q\n", ascii)   // "97 a 'a'"
	fmt.Printf("%d %[1]c %[1]q\n", unicode) // "22269 国 '国'"
	fmt.Printf("%d %[1]q\n", newline)       // "10 '\n'"

}
