Go语言的基本数据类型:整型、浮点型、字符串

目录

【整型int】

整型溢出

整型字面值

【浮点型float】

浮点型字面值

复数类型

【字符串string】

Go 字符串类型的内部表示

Go 字符串类型的常见操作

关于整型、浮点型、字符串 的一些其它示例:

字符串和数值类型的转换

【创建自定义数据类型】

【输出方法Print】

【运行测试】


Go语言中的基本数据类型包括下面这些:

基本数据类型
bool
string
int int8 int16 int32 int64
uint uint8 uint16 uint32 uint64 uintptr
byte // alias for uint8
rune // alias for int32,represents a Unicode code point
float32 float64
complex64 complex128

【整型】

分为平台无关整型和平台相关整型这两种,平台无关整型在任何 CPU 架构或任何操作系统下面,长度都是固定不变的。

 byte 等同于 uint8;rune 等同于 int32

平台相关整型的长度会根据运行平台的改变而改变。Go语言原生提供了三个平台相关整型,它们是 int、uint 与 uintptr。

在编写有移植性要求的代码时,千万不要强依赖这些类型的长度,可以通过 unsafe 包提供的 SizeOf 函数来获取。

var ao, bo = int(5), uint(6)
var p uintptr = 0x12345678
fmt.Println(unsafe.Sizeof(ao)) // 8
fmt.Println(unsafe.Sizeof(bo)) // 8
fmt.Println(unsafe.Sizeof(p))  // 8

整型溢出

如果整型的结果超出了它的边界值,就会发生整型溢出问题。出现溢出情况后,对应的整型变量的值依然会落到它的取值范围内,只是结果值与预期不符。这个问题最容易发生在循环语句的结束条件判断中,因为这也是经常使用整型变量的地方。

var num int8 = 127
num += 1
fmt.Println(num) //期望结果128,实际-128

var num2 uint8 = 1
num2 -= 2
fmt.Println(num2) //期望结果-1,实际255

整型字面值

a := 53 // 十进制
b := 0700 // 八进制,以"0"为前缀
c1 := 0xaabbcc // 十六进制,以"0x"为前缀
c2 := 0Xddeeff // 十六进制,以"0X"为前缀

//Go 1.13 版本中,Go 又增加了对二进制字面值的支持和两种八进制字面值的形式
d1 := 0b10000001 // 二进制,以"0b"为前缀
d2 := 0B10000001 // 二进制,以"0B"为前缀
e1 := 0o700 // 八进制,以"0o"为前缀
e2 := 0O700 // 八进制,以"0O"为前缀

//Go 1.13 版本还支持在字面值中增加数字分隔符“_”,分隔符可以用来将数字分组以提高可读性。
a := 5_3_7 // 十进制: 537
b := 0b_1000_0111 // 二进制位表示为10000111
c1 := 0_700 // 八进制: 0700
c2 := 0o_700 // 八进制: 0700
d1 := 0x_5c_6d // 十六进制:0x5c6d

//通过标准库 fmt 包的格式化输出函数,将一个整型变量输出为不同进制的形式
var a int8 = 59
fmt.Printf("%b\n", a) //输出二进制:111011
fmt.Printf("%d\n", a) //输出十进制:59
fmt.Printf("%o\n", a) //输出八进制:73
fmt.Printf("%O\n", a) //输出八进制(带0o前缀):0o73
fmt.Printf("%x\n", a) //输出十六进制(小写):3b
fmt.Printf("%X\n", a) //输出十六进制(大写):3B

【浮点型】

Go 语言提供了 float32 与 float64 两种浮点类型,默认值都是0.0,但是它们占用的内容空间大小不一样,并且可表示的浮点数的范围和精度也不一样。一般比较常用的float64是双精度,float32由于精度不足可能会导致输出结果出现异常,比如下面的代码:

var x1 float32 = 16777216.0
var x2 float32 = 16777217.0
fmt.Println("x1==x2? ", x1 == x2) // true

浮点型字面值

//用十进制表示的浮点值形式
float1 := 3.1415
float2 := .15 // 整数部分如果为0,整数部分可以省略不写
float3 := 81.80
float4 := 82. // 小数部分如果为0,小数点后的0可以省略不写

//十进制的科学计数法形式(e/E 代表的幂运算的底数为 10)
float5 := 6674.28e-2 // 6674.28 * 10^(-2) = 66.742800
float6 := .12345E+5 // 0.12345 * 10^5 = 12345.000000

//十六进制科学计数法形式( p/P 代表的幂运算的底数为 2)
float7 := 0x2.p10 // 2.0 * 2^10 = 2048.000000
float8 := 0x1.Fp+0 // 1.9375 * 2^0 = 1.937500

//通过 %f 可以输出浮点数最直观的原值形式
var f9 float64 = 123.45678
fmt.Printf("%f\n", f9) // 123.456780
//将浮点数输出为科学计数法形式
fmt.Printf("%e\n", f9) // 1.234568e+02 //十进制的科学计数法
fmt.Printf("%x\n", f9) // 0x1.edd3be22e5de1p+06 //十六进制的科学计数法

Go 语言中没有提供 float 类型。这不像整型那样既提供了 int16、int32 等类型又有 int 类型。也就是说:Go 提供的浮点类型都是平台无关的。

复数类型

复数类型分别是 complex64 和 complex128,complex64 的实部与虚部都是 float32 类型,而 complex128 的实部与虚部都是 float64 类型。如果一个复数没有显示赋予类型,那么它的默认类型为 complex128。下面是表示复数字面值的方法:

//第一种,可以通过复数字面值直接初始化一个复数类型变量
var c = 5 + 6i
var d = 0o123 + .12345E+5i // 83+12345i

//第二种,通过complex 函数创建一个 complex128 类型值
var c = complex(5, 6) // 5 + 6i
var d = complex(0o123, .12345E+5) // 83+12345i

//第三种,通过 real 和 imag 函数来获取一个复数的实部与虚部,返回值为一个浮点类型
var c = complex(5, 6) // 5 + 6i
r := real(c) // 5.000000
i := imag(c) // 6.000000

【字符串】

Go语言中的字符串类型的值在它的生命周期内是不可改变的,最大好处就是不用再担心字符串的并发安全问题,这样字符串可以被多个 Goroutine 共享,不用担心并发安全问题。另外也由于字符串的不可变性,针对同一个字符串值无论在程序的几个位置被使用,Go 编译器只需要为它分配一块存储就好了,大大提高了存储利用率。

var s string = "hello"
s[0] = 'k' // 错误:字符串的内容是不可改变的
s = "gopher" //可以重新赋值

Go 采用的是 Unicode 字符集,每个字符都是一个 Unicode 字符。打印字符串中的每个字节,以及整个字符串的长度:

var s = "中国人"
fmt.Printf("the length of s = %d\n", len(s)) // 9
for i := 0; i < len(s); i++ {
fmt.Printf("0x%x ", s[i]) // 0xe4 0xb8 0xad 0xe5 0x9b 0xbd 0xe4 0xba 0xba
}
fmt.Printf("\n")

通过字符序列的视角来看字符串

var s = "中国人"
fmt.Println("the character count in s is", utf8.RuneCountInString(s)) // 3
for _, c := range s {
fmt.Printf("0x%x ", c) // 0x4e2d 0x56fd 0x4eba
}
fmt.Printf("\n")

Go 字符串类型的内部表示

string 类型其实是一个“描述符”,它本身并不真正存储字符串数据,而仅是由一个指向底层存储的指针和字符串的长度字段组成的。获取字符串长度的时间复杂度是O(1)

// $GOROOT/src/reflect/value.go

// StringHeader是一个string的运行时表示
type StringHeader struct {
    Data uintptr
    Len int
}

因此,直接将 string 类型通过函数 / 方法参数传入也不会带来太多的开销。因为传入的仅仅是一个“描述符”,而不是真正的字符串数据。 

Go 字符串类型的常见操作

1、在字符串的实现中,真正存储数据的是底层的数组,因此一般可以使用字符串的下标获取某个字节(而不是字符)

var s = "中国人"
fmt.Printf("0x%x\n", s[0]) // 0xe4:字符“中” utf-8编码的第一个字节

2、使用 for 与 for range 迭代字符串,这两种形式的迭代对字符串进行操作得到的结果是不同的。

//字节视角的迭代,使用 for
var s = "中国人"
for i := 0; i < len(s); i++ {
    fmt.Printf("index: %d, value: 0x%x\n", i, s[i])
}

//字符串中 Unicode 字符的码点值,使用 for ... range
var s = "中国人"
for i, v := range s {
    fmt.Printf("index: %d, value: 0x%x\n", i, v)
}

常⽤字符串函数
1. strings 包:https://golang.org/pkg/strings 
2. strconv 包:https://golang.org/pkg/strconv 

关于整型、浮点型、字符串 的一些其它示例:

//go01/data_type.go

package main

import "fmt"

func main() {
	//1.布尔类型
	var b1 bool
	b1 = true
	fmt.Printf("b1: %T,%t\n", b1, b1)
	b2 := false
	fmt.Printf("b2: %T,%t\n", b2, b2)
    //bool类型占用存储空间是1个字节
	fmt.Println("b2 的占用空间 =", unsafe.Sizeof(b2)) //1

	//2.整数
	var i1 int8
	i1 = 100
	fmt.Println(i1)
	var i2 uint8
	i2 = 200
	fmt.Println(i2)

	var i3 int
	i3 = 1000
	fmt.Println(i3)
	//语法角度:int,int64不认为是同一种类型
	//var i4 int64
	//i4 = i3 //cannot use i3 (type int) as type int64 in assignment

	var i5 uint8
	i5 = 100
	var i6 byte
	i6 = i5
	fmt.Println(i5, i6)

	var i7 = 100
	fmt.Printf("%T,%d\n", i7, i7)

	//浮点
	var f1 float32
	f1 = 3.14
	var f2 float64
	f2 = 4.67
	fmt.Printf("f1: %T,%.2f\n", f1, f1)
	fmt.Printf("f2: %T,%.3f\n", f2, f2)
	fmt.Println(f1)

	var f3 = 2.55
	fmt.Printf("f3: %T\n", f3)

	//字符串
	//1.定义字符串
	var s1 string
	s1 = "你好"
	fmt.Printf("s1: %T,%s\n", s1, s1)

	s2 := `Hello World`
	fmt.Printf("s2: %T,%s\n", s2, s2)

	//2.区别:'A',"A"
	v1 := 'A'
	v2 := "A"
	fmt.Printf("v1: %T,%d\n", v1, v1) //int32
	fmt.Printf("v2: %T,%s\n", v2, v2)

	v3 := '中'
	fmt.Printf("v3: %T,%d,%c,%q\n", v3, v3, v3, v3)

	//3.转义字符
	fmt.Println("\"HelloWorld\"")
	fmt.Println("Hello\nWor\tld")
	fmt.Println(`He"lloWor"ld`)
	fmt.Println("Hello`Wor`ld")

    //字节长度:和编码无关,用 len(str)获取
	fmt.Println(len("ab")) //2
	fmt.Println(len("你好")) //6

	//字符数量:和编码有关,用编码库来计算
	fmt.Println(utf8.RuneCountInString("ab")) //2
	fmt.Println(utf8.RuneCountInString("你好")) //2

    //字符串拼接,用 + 号
	sk1 := "你好"
	sk2 := "再见"
	fmt.Println(sk1 + sk2) //你好再见

    //指针对应的是变量在内存中的存储位置,也就是说 指针的值就是变量的内存地址
	dat := 10
	datP := &dat  //data的指针
    // datP = datP + 1 //报错:指针不支持运算
	datV := *datP //dataP指针对应的值
	fmt.Println(datP, datV) //0xc00001e1a0    10
    fmt.Printf("%T %T \n", datP, datV) //*int int

    //判断数据类型
	data := "个人信息"
	fmt.Println(getVarType(data)) //string
}

func getVarType(args interface{}) string {
	switch args.(type) {
	case nil:
		return "nil"
	case int:
		return "int"
	case int64:
		return "int64"
	case float64:
		return "float64"
	case bool:
		return "bool"
	case string:
		return "string"
	case func(int) float64:
		return "func(int)"
	default:
		return "unknown"
	}
}

/*字符串分割成数组,以及数组拼接成字符串*/
func stringFn(s string) {
	parts := strings.Split(s, ",")
	for _, part := range parts {
		fmt.Println(part)
	}
	fmt.Println(strings.Join(parts, "-"))
}

字符串和数值类型的转换

var str string = "true"
var b bool
b, _ = strconv.ParseBool(str)
fmt.Printf("b type %T  b=%v\n", b, b) //b type bool  b=true

var str2 string = "1234590"
var n1 int64
var n2 int
n1, _ = strconv.ParseInt(str2, 10, 64)
n2 = int(n1)
fmt.Printf("n1 type %T  n1=%v\n", n1, n1) //n1 type int64  n1=1234590
fmt.Printf("n2 type %T n2=%v\n", n2, n2)  //n2 type int n2=1234590

var str3 string = "123.456"
var f1 float64
f1, _ = strconv.ParseFloat(str3, 64)
fmt.Printf("f1 type %T f1=%v\n", f1, f1) //f1 type float64 f1=123.456

var str4 string = "hello"
var n3 int64 = 11
n3, _ = strconv.ParseInt(str4, 10, 64)
fmt.Printf("n3 type %T n3=%v\n", n3, n3) //n3 type int64 n3=0

【创建自定义数据类型】

//MyInt的数值性质与 int32 完全相同
type MyInt int32

//但仍然是完全不同的两种类型,无法直接让它们相互赋值或放在同一个运算中直接计算
var m int = 5
var n int32 = 6
var a MyInt = m // 错误:在赋值中不能将m(int类型)作为MyInt类型使用
var a MyInt = n // 错误:在赋值中不能将n(int32类型)作为MyInt类型使用

//需要显示的转换类型才可以
var a MyInt = MyInt(m) // ok
var a MyInt = MyInt(n) // ok

//也可以通过类型别名(Type Alias)来自定义数值类型,此时定义的新类型与原类型没有区别
type YourInt = int32
var n int32 = 6
var a YourInt = n // ok

【输出方法Print】

fmt.Print:输出到控制台(仅只是输出)

fmt.Println:输出到控制台并换行

fmt.Printf:仅输出格式化的字符串和字符串变量(整型和整型变量不可以)

fmt.Sprintf:格式化并返回一个字符串,不输出。

//go01/print.go

package main

import (
	"fmt"
)

func main() {
	fmt.Print("输出到控制台不换行--- ")
	fmt.Println("输出到控制台并换行")
	fmt.Printf("name=%s,age=%d\n", "Tom", 30)
	fmt.Printf("name=%s,age=%d,height=%v\n", "Tom", 30, fmt.Sprintf("%.2f", 180.567))
}

【运行测试】

编写测试程序
1.源码⽂文件以 _test 结尾:xxx_test.go
2.测试⽅方法名以 Test 开头:func TestXXX(t *testing.T) {...}
运行方法: go test -v run_test.go

//go01/run_test.go

package main_test

import "testing"

const (
	Monday = 1 + iota
	Tuesday
	Wednesday
)

func TestPoint(t *testing.T) {
	t.Log(Monday, Tuesday, Wednesday)
	a := 1
	aPtr := &a
	t.Log(a, aPtr)
	t.Logf("%T %T", a, aPtr)
}

源代码:go-demo-2023: Go语言基本用法和实用笔记 - Gitee.com 

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

浮尘笔记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值