.\main.go:8:21: constant 1000 overflows uint8
在Python里面定义1个数字类型的变量,无需考虑系统底层内存存储这个变量 需要开销多大 存储空间(位),因为Python解释器自动计算、分配;
在Go里面不行!Go语言的整型分为有符号整型和无符号整型2大类。
计算机只认识0、1,所谓有符号和无符号就是 计算机到底需要分配多大的存储空间(位/字节)来存储这些数字。
有符号整型:计算机
使用第0位表示数字的
+正 -负性质
,其他位用来表示数字。(可表示负数,但是表示正数的范围小!)
无符号整型:计算机使用全部的位 来表示数字(不可以表示负数,但是可表示正数的范围很大!)
综上所述:
有符号整型
:表示数字的位 比无符号少了1位,所以有符号整型可
表示负数,但是表示正数字范围小。
无符号整型
:没有符号位
无法表示负数,但是表示正数的范围会更大。
所有我们需要根据
数字的大小范围来选择合适的整数的类型
。
注意即便uint8和uint20同属于整型和无符号整型,也有不同数据类型之分。
有符号整型:
int8、int16、int32、int64
无符号整型:
uint8、uint16、unit32、uint64
不同整型之间的相互转换
在go语言中不同位的整型相互转换时,由低位转成高位,不会有问题,但是由高位转换成低位就会表示错误。
func main() {
var v1 int8=10
var v2 int16=19
//整型数据类型转换
v3:=int16(v1)+v2
fmt.Println(v3,reflect.TypeOf(v3))//29 int16
//低位转向高位,没问题。高位转低位无法转
var v4 int16 = 2020
v5:=int8(v4)
fmt.Println(v5)//注意这里不会报错,而是轮回转换。
整型和字符串之间的转换(strconv)
使用strconv.Atoi(string)可以把字符转换成整型,trconv.Itoa(int)把数字转换成字符串。
//2.整型和字符串类型之间的的转换
var str1 string ="132201988666"
fmt.Println(strconv.Atoi(str1))
number2:=13220198866
//strconv.Itoa()只能转换int类型
fmt.Println(strconv.Itoa(number2))
不同进制之间的转换
人类使用10进制计算,计算机使用二进制(一大堆0和1)进行运算。
通常计算机使用八进制和十六进制去更精简地显示二进制给人类看。
既然人类熟悉10进制,那么把二进制转换成10进制给人类显示,岂不更方便?
因为10进制不如8进制和16进制那样,在计算机中方便运算。
1.十进制(整型)转换成 二进制、八进制、十六进制
在go语言中十进制是以整型的方式存在,其进制(二进制、八进制、十六进制)均已字符串的形式存在。
var n1 int64 =190
//十进制转换成二进制
binaryNumber:=strconv.FormatInt(n1,2)
fmt.Println(binaryNumber)//string
fmt.Println(reflect.TypeOf(binaryNumber))
//十进制转换成8进制
octalNumber:=strconv.FormatInt(n1,8)
fmt.Println(octalNumber)//string
fmt.Println(reflect.TypeOf(octalNumber))
//十进制转成16进制
hexadecimalNumber:=strconv.FormatInt(n1,16)
fmt.Println(hexadecimalNumber)
fmt.Println(reflect.TypeOf(hexadecimalNumber))//string
2.二进制、八进制、十六进制(字符串)转换成十进制(int64位整型)
我们使用strconv.Format(十进制,想要的进制 ),可以把十进制(整型)转成二进制、八进制、十六进制的字符串。
使用strconv.ParseInt(), 把二进制、八进制、十六进制(字符串)转换成十进制(整型)。
var barnaryNumber,octalNumber,hexadecimalNumber string ="10111110","276","be"
fmt.Println(strconv.ParseInt(barnaryNumber,2,16))
//2:把字符串barnaryNumber当做二进制去转换成十进制,
//16:转换过程中对十进制结果数字大小范围进行约束
//result永远以int64的类型返回
fmt.Println(strconv.ParseInt(octalNumber,8,16))
fmt.Println(strconv.ParseInt(hexadecimalNumber,16,16))
常见的数学运算
package main
import (
"fmt"
"math"
func main() {
fmt.Println(math.Abs(-19)) //获取绝对值:19
fmt.Println(math.Floor(3.14)) //向下取整
fmt.Println(math.Ceil(3.14)) //向上取整
fmt.Println(math.Round(3.1678)) //自动(四舍五入)取整数
fmt.Println(math.Round(3.1678*100)/100)//自动保留小数点后2位
fmt.Println(math.Mod(11, 3)) //获取余数
fmt.Println(math.Pow(2, 2)) //求2的2次方
fmt.Println(math.Pow10(2)) //求2的10次方
fmt.Println(math.Max(3, 5)) //获取较大
fmt.Println(math.Min(3, 5)) //获取较小
超大数值整型
当我们要使用的数字超过了64位可以表示的范围,可以使用big.Int。
package main
import (
"fmt"
"math/big"
func main() {
//1.创建1个超大整型的对象
var v1 big.Int
//var v2 *big.Int
v3:=new(big.Int)
//2.在超大整型对象中写入1些值
v1.SetInt64(1993)
//支持以字符串的形式写入到内存,以10进制的形式
v1.SetString("9012308480889",10)
v3.SetString("10000000000000000000",10)
fmt.Println(v1,v3)
//3.超大整型操作(加减乘除)
n1:=new(big.Int)
n1.SetString("19999999991111",10)
n2:=new(big.Int)
n2.SetString("7777777777",10)
result:=new(big.Int)
result.Add(n1,n2)
fmt.Println(result)
result.Sub(n1,n2)
fmt.Println(result)
result.Mul(n1,n2)
fmt.Println(result)
result.Div(n1,n2)
fmt.Println(result)
//除:得到商和余数 求页码时使用
minder:=new(big.Int)
result.DivMod(n1,n2,minder)
fmt.Println(result,minder)
//把bigint转换成int64
fmt.Println(result.Int64())
//把bigint转换成字符串
fmt.Println(result.String())
int、uint、rune、byte
在Go语言中数字的默认数据类型是int类型,也就是有符号整型,如果是32的操作系统就是int32如果是64位操作系统就是int64
package main
import (
"fmt"
"unsafe"
func main() {
var n1 = 100
//n1的数据类型:int n1占用的字节数是8我的电脑是64位所以就是 int64 8位=1字节=8字节
fmt.Printf("n1的数据类型:%T n1占用的字节数是%d \n", n1, unsafe.Sizeof(n1))
//在程序运行中,尽量使用占用空间减少的数据类型 比如年龄的数字范围1-200足矣,不需要用int64
var age byte = 19
println(age)
整型变量的声明方式
为什么每中编程语言都有数据类型?
就是可以满足我们声明多样化的数据结构变量的需求,我们的程序逻辑可以处理各种各样的变量(数据)时,我们就可以完成更多的功能。
package main
import "fmt"
func main(){
//方法1:先声明再赋值
var n1 int32
n1=10
//方法2:var 声明时一起赋值
var n2 int8 =10
//方法3:简短声明自动推断19为默认为int类型
n3:=18
//方法4:int类型强制转换为int16
var n4=int16(19)
fmt.Printf("%T,%T,%T,%T",n1,n2,n3,n4)
浮点型为什么无法精准表示?
计算机只认识0和1,想要明白这个问题,得说到浮点型是怎么转换成二进制进行存储的。
例如:声明1个变量 var price float32 =39.29
第一步:把浮点型 39.29转换成二进制
整数部分(39/十进制)直接转换成二进制:39----->100111
小数部分:让小数乘2,结果小于1则继续乘2,如果大于1则让结果减1再继续乘2,一直等到*2=1则结束。
得出浮点型,小数部分的二进制
结果的整数部分拼接起来,所以0.29的二进制就是---->01001010001111010111000........................
问题就出在这:39.29的小数部分0.29,这特么永远得不出1,导致fraction位无法完整存储浮点型小数部分的二进制!丢失精度了!
但是有的小数是可以的例如:0.5所以并不是所有小数都会出现精度丢失的问题。
经过以上步骤39.29的二进制就100111.01001010001111010111000........................
第二步:科数据计数法表示二进制
科数计数法就是把1个数字变成1.x乘2的多少次方。向左移了几位就是2的几次方,如果向右移了几位就是2的负几次方。
科数计数法发表示:100111.01001010001111010111000........................
第三步:存储到科学计数法表示的二进制
以flaot32位进行表示
sign:表示浮点型的正负,0表示正数、1表示负数
exponent(指数):存储科学技术法的指数(几次方),exponent有8位所以表示范围=-128至127,这8位既可以表示负指数 也可以表示正值数。
例如:指数是5 那么5得+127。
为什么+5得加127,因为如果再来个是1个-5,岂不是和+5表示重叠了!
5+127=132转换乘二进制10000100存储到exponent.
fraction(小数):存储浮点型小数部分二进制的01001010001111010111000........................超出32/64位直接丢弃!这就是浮点型无法精确表示的原因。
decimal第三方包精确表示浮点型
尤其是面向电商领域开发,特别需要浮点型。
你就不得不解决浮点型精度丢失的问题,golang的decimal包可以解决这个问题。
package main
import (
"fmt"
"github.com/shopspring/decimal"
func main() {
var v1 =decimal.NewFromFloat(0.0000019)
var v2 =decimal.NewFromFloat(0.298766)
var v3 =v1.Add(v2)
var v4 =v3.Sub(v2)
var v5 =v4.Mul(v2)
var v6 =v4.Div(v1)
fmt.Println(v3)
fmt.Println(v4)
fmt.Println(v5)
fmt.Println(v6)
var price=decimal.NewFromFloat(3.6615926)
fmt.Println(price.Round(1)) //保留小数点后1位自动四舍五入
fmt.Println(price.Truncate(2))//保留小数点后2位不需要四舍五入
coplex128
complex64
Go里面的布尔值不能像Python那样和0和1做转换
false
func main() {
//字符串转换成布尔类型
// "1", "t", "T", "true", "TRUE", "True"都可以转换成true
//"0", "f", "F", "false", "FALSE", "False" 都可以转换成false
reslut,err:=strconv.ParseBool("True")
fmt.Println(reslut,err)
//布尔类型转换成字符串
reslut1:=strconv.FormatBool(true)
fmt.Println(reslut1)
Go语言的字符有以下两种:
一种是 uint8 类型,或者叫 byte 型,代表了 ASCII 码的一个字符的编码。
另一种是 rune 类型,代表一个 UTF-8 字符的编码,当需要处理中文、日文或者其他复合字符时,则需要用到 rune 类型。rune 类型等价于 int32 类型。
Go的字符串是由Utf-8编码之后的字节序列,所以不能修改,1个汉字占用3个字节、1个英文字母占用1个字节的存储空间。
go使用rune(1个int32类型的数字) 表示中文字符,使用byte(1个uint8类型的数字)表示英文。
字节切片和rune切片的区别是:
rune切片直接存储Unicode(ucs4)中字符串对应的码位,字节切片则存储码位被utf-8编码之后的utf8码。
package main
import (
"fmt"
"strconv"
"unicode/utf8"
func main() {
//1.go语言中的字符串本质上是utf-8编码之后的字节序列
var name string="张根"
fmt.Println(name)
//utf-8的第三个模板:1110XXXX 10XXXXXX 10XXXXXX
//张 utf-8码=根据张字符在Unicode的码位codepoint进行utf-8编码所得 1110【0101】 10【111100】 10【100000】
fmt.Println(strconv.FormatInt(int64(name[0]),2),strconv.FormatInt(int64(name[1]),2),strconv.FormatInt(int64(name[2]),2)) //
//根 utf-8码=根据张字符在Unicode的码位codepoint进行utf-8编码所得 11100110 10100000 10111001
fmt.Println(strconv.FormatInt(int64(name[3]),2),strconv.FormatInt(int64(name[4]),2),strconv.FormatInt(int64(name[5]),2))
//2.获取字符串的长度其实就是获取utf-8编码之后字节的长度。即6个字节
fmt.Printf("字节长度%d\n",len(name))
//3.字符串转换成---》1个字节切片
byteSlice:=[]byte(name)
fmt.Println(byteSlice)
//4.字节切片转换成----》1个字符串
togetByteSlice:=[]byte{229,188,160,230,160,185}
togetString:=string(togetByteSlice)
fmt.Println(togetString)
//5.rune也是golang里的1种数据类型:它表示的的是字符串在Unicode(ucs4)字符集中对应的码位
runeSet:=[]rune(name) //[24352 26681]
fmt.Println(runeSet)
//张 在Unicode字符集中的码位:二进制:10111110 0100000 十六进制:5f20
//utf-8编码的机制:(101)(111100)(100000)--->1110XXXX 10XXXXXX 10XXXXXX --->1110【0101】 10【111100】 10【100000】
fmt.Println(strconv.FormatInt(int64(runeSet[0]),2))
fmt.Println(strconv.FormatInt(int64(runeSet[0]),16))
//根 在Unicode字符集的的码位:二进制:11010000 0111001 十六进制:6839
fmt.Println(strconv.FormatInt(int64(runeSet[1]),2))
fmt.Println(strconv.FormatInt(int64(runeSet[1]),16))
//6.rune切片转换成字符串
runeList:=[]rune{24352,26681}
fmt.Println(string(runeList)) //张根
//7.获取字符串的字面长度 牛魔王 3个长度
nickName:="牛魔王"
runeLenth:=utf8.RuneCountInString(nickName)
fmt.Println(runeLenth)
golang字符串底层实现原理
Python字符串的index方法:
a="1111"
print((a.index("2")))
#找不到指定的元素Python报错:ValueError: substring not found
Golang字符串中的strings.index()方法:
package main
import (
"fmt"
"strings"
func main() {
testString := "Hello"
index := strings.Index(testString,"W")
fmt.Println(index)//找不到指定元素返回-1
practice
自定义1个string的split方法
package main
import (
"fmt"
"strings"
func main() {
str1 := "123a456a789"
sep := "a"
var ret []string
//a的index
index := strings.Index(str1, sep)
//知道字符串中不包含a也就是index=-1为止
for index >= 0 {
//a位置之前的部分:123
ret = append(ret, str1[:index])
//a位置之后的部分:456a789
str1 = str1[index+1:]
index = strings.Index(str1, sep)
ret = append(ret, str1)
fmt.Println(ret)
fmt.Println(utf8.RuneCountInString(name))
//2.判断字符串开头?
if strings.HasPrefix(name,"张"){
fmt.Print("我姓张")
//3.判断字符串结尾?
if strings.HasSuffix(name,"根"){
fmt.Print("名根。\n")
//3.判断字符串是否包含?
str1:="抬老子的意大利炮来。"
if (strings.Contains(str1,"老子")){
fmt.Println("别说脏话!")
//4.字符串小大写转换:验证码对大小写不敏感
realName:="Martin"
upperName:=strings.ToUpper(realName)
fmt.Println(upperName)
LowerName:=strings.ToLower(upperName)
fmt.Println(LowerName)
//5.去除2边、 前缀、后缀
string2:="ABC"
result2:=strings.TrimRight(string2,"C")
fmt.Println(result2)
result3:=strings.TrimLeft(string2,"A")
fmt.Println(result3)
string3:=" ABC"
//ps.去除两端的空格:在Python和JS中trim()没有参数自动去除空,但是go语言需要,写上空字符串
result4:=strings.Trim(string3," ")
fmt.Println(result4)
//6.字符串替换
string4:="zhanggen"
//从左到右找到第1个进行替换
result5:=strings.Replace(string4,"g","G",1)
fmt.Println(result5)
//从左到右找到前2个”g“进行替换
result6:=strings.Replace(string4,"g","G",2)
fmt.Println(result6)
//替换所有“2”
result7:=strings.Replace(string4,"n","N",2)
fmt.Println(result7)
//7.字符串分割成string切片
string5:="1 2 3"
result8:=strings.Split(string5," ")
fmt.Println(result8,reflect.TypeOf(result8)) //[]string
//8.字符串拼接
//+不建议
message:="我爱北京"+"天安门"
fmt.Println(message)
//效率高一些
stringList:=[]string{"我","爱","北京"}
result9:=strings.Join(stringList,"")
fmt.Println(result9)
//效率更高一些: go 1.10之前
var buffer bytes.Buffer
buffer.WriteString("我爱")
buffer.WriteString("北京")
buffer.WriteString("天安门")
result10:=buffer.String()
fmt.Println(result10)
//效率更高一些: go 1.10之后
var builder strings.Builder
builder.WriteString("我爱")
builder.WriteString("北")
builder.WriteString("京")
result11:=builder.String()
fmt.Println(result11)
//9.字符串和整型之间相互转换:Atoi/ItoO
var message1 string ="666"
number,err:=strconv.Atoi(message1)
if err==nil{
fmt.Println(number,reflect.TypeOf(number))
fmt.Println(strconv.Itoa(number),reflect.TypeOf(strconv.Itoa(number)))
//字符串转数字:64:转换过程中对十进制结果数字大小范围进行约束
number1,err:=strconv.ParseInt("1111000",2,64)
fmt.Println(number1,err,reflect.TypeOf(number1))
//10进制转2进制
decimalDigit:=strconv.FormatInt(int64(120) ,2,)
fmt.Println(decimalDigit)
//10.字符串和字节切片之间的转换
name2:="张纪中"
//字符串转换成字节集合:字节切片本质上是二进制但是以10进制的方式显示出来。
byteSet:=[]byte(name2)
fmt.Println(byteSet)
//字节集合转换成字符串
byteList:=[]byte{229,188,160,231,186,170,228,184,173}
fmt.Println(string(byteList))
//11.字符串和rune切片之间的转换
name3:="张艺谋"
runeSet:=[]rune(name3)
fmt.Println(runeSet)
//rune int32的别名
runeSlice:=[]rune{24352,33402,35851}
fmt.Println(string(runeSlice))
fmt.Println()
//12.string和字符:根据Unicode的码位进行转换(应用生产随机验证码)
v1:=string(26681)
fmt.Println(v1,reflect.TypeOf(v1))
//字符串转数字
v2,size:=utf8.DecodeRuneInString("A")
fmt.Println(v2,size) //65 1个字节表示1个英文字符
v3,size:=utf8.DecodeRuneInString("根")
fmt.Println(v3,size) //26681 3个字节表示1个汉字
字符串常见操作
package main
import (
"fmt"
"strings"
"unicode"
func main() {
s1 := "D:\\goproject\\src"
//字符相关操作
//字符串长度
fmt.Println(len(s1))
//字符串拼接
FirstName := "Martin"
LastName := "Zhang"
FullName := FirstName + LastName
fmt.Println(FullName)
FullName2 := fmt.Sprintf("%s%s", LastName, FirstName)
fmt.Println(FullName2)
//字符串分割
s3 := "D:\\goproject\\src"
ret := strings.Split(s3, "\\")
fmt.Println(ret)
fmt.Println(strings.Contains(s3, "D"))
//判断字符串 的开头和结尾判断
fmt.Println(strings.HasPrefix(s3, "D"))
fmt.Println(strings.HasSuffix(s3, "src"))
//判断字符在字符串中的index
s2 := "abcdeb"
fmt.Println(strings.Index(s2, "b"))
fmt.Println(strings.LastIndex(s2, "b")) //最后1次出现的位置
//字符串拼接
s4 := "D:\\goproject\\src"
ret4 := strings.Split(s4, "\\")
s5 := strings.Join(ret4, "/")
fmt.Println(s5)
//字符串表里
//字符:组成字符串的每1个元素 我们称之为字符,在go语言里通过''单引号来定义字符
//在go语言里字符分为2种:1种是byte 1种是rune
//byte:给ascii 编码的字符起的别名
//rune:给Unicode编码的字符起的别名
var c1 byte = 'c'
var c2 rune = '中'
fmt.Printf("c1:%T c2:%T\n", c1, c2)
s6 := "hello 张根"
//for 循环 按照1个字节循环(会出现乱码:因为中文和英文占用的字节不一致)
// for i := 0; i < len(s6); i++ {
// fmt.Printf("%c\n", s6[i])
//for range 按1个字符循环
for _, v := range s6 {
fmt.Printf("%c\n", v)
//字符串修改
s7 := "白萝卜"
s8 := []rune(s7) //把字符串强制转换为runne切片就可以修改字符串了
s8[0] = '红' //修改第一个字符
fmt.Println(string(s8))
//类型转换
n := 10
var f float64
f = float64(n) //整型 转成 float64类型
fmt.Println(f)
fmt.Printf("%T\n", f) //float64
//判读数据类型
s9 := "Hello张根"
for _, v := range s9 {
if unicode.Is(unicode.Han, v) {
fmt.Print(string(v))
字符串的索引和循环遍历
Golang的字符串和Python中的字符串存储机制上有很大区别,Python中的字符串直接是Unicode中的字符,直接同过索引获取即可。(学的这里我仿佛感受到了Python其实帮我们做了很多很多事情....)
Golang中字符串是utf-8编码之后的字节序列,所以我们通过索引获取到的是字节(其实是一堆utf-8编码之后的0和1,显示是按10进制显示出来的)并非字符本身。
runn 切片可以帮我们解决这种问题,如果把1个字符串转换成rune切片那么这个rune切片中就存储了字符串中每1个字符在Unicode字符集中对应的码位。
既然得到每1个字符的码位 就好比1个工作在凌晨3点的程序员得到了老板让先下班回家的指令, 好比拿到了数据库里1个记录的index,string(codepoint)就可以拿到字符了。
package main
import "fmt"
func main() {
//1.索引获取字节
var name= "大根子"
//获取字字节序列的第1个字节
fmt.Println(name[0])
//第2个
fmt.Println(name[1])
//第3个
fmt.Println(name[2])
//2.获取字节区间:获取3个字节
fmt.Println(name[0:3]) //
//3.循环获取蓑鲉字节
for i:=0;i<len(name);i++{
fmt.Println(i,name[i])
//4.for range获取所有字符,
//for range字符串相当于把字符串转换成了rune切片,进行循环
for index,item:=range name{
fmt.Println(index,string(item))
//5.转成rune集合获取字符
dataList:=[]rune(name)
fmt.Println(dataList[0],string(dataList[0]))
字符串正确的索引和循环方式
字符(char)
在Go中有字符的概念,使用单引号表示,需要注意的是,英文字符和中文字符,
Go 使用int 的 数据类型别名的方式来表示字符。其中rune为int32的数据类型别名表示中文,byte为uint8的数据类型别名用于表示英文
什么是数据类型别名?
In a nutshell just an other name name data type of Golang by you like way.
。。...
package main
import "fmt"
var c1 byte = 'c'
var c2 rune = '中'
type myInt = int
func main() {
var n myInt
n = 100
fmt.Printf("%T\n",n)//%T\n Myint还是int
fmt.Printf("%T\n", c1) //uint8
fmt.Printf("%T\n", c2) //int32