Go语言基础--数据类型相互转换、指针

数据类型默认值

  1. 布尔类型(bool)false

  2. 整型(int、int8、int16、int32、int64、uint、uint8、uint16、uint32、uint64)0

  3. 浮点型(float32、float64)0.0

  4. 复数类型(complex64、complex128)(0+0i),其中i是虚数单位

  5. 字符串(string) :空字符串""

  6. 字节切片([]byte)nil,但如果是作为结构体字段或数组元素,则会被初始化为长度为0的切片(即[]byte{},但注意这仅适用于全局变量或结构体字段的自动初始化,局部变量仍会是nil

  7. 其他切片(如[]intnil,但同样,如果作为结构体字段或数组元素,则会被初始化为长度为0的切片(如[]int{}

  8. 映射(map)nil

  9. 通道(chan)nil

  10. 接口(interface{})nil

  11. 结构体(struct):结构体中每个字段都会被初始化为该字段类型的零值。如果结构体包含其他结构体或指针等,这些也会被递归地初始化为它们的零值。

  12. 指针(*T)nil,其中T是任意类型

  13. 函数(func) :函数类型没有零值的概念,因为函数不是变量,而是可以被调用的代码块。但是,函数类型的变量(即函数指针)的零值是nil。

基本数据类型相互转换

基本数据类型转string

fmt.Sprintf("%参数", 表达式) 会返回转换后的字符串

package main

import (

"fmt"

_"strconv"

)

func main() {

i := 123

s := fmt.Sprintf("%d", i) // 将int转换为string

fmt.Println(s, "is a string")

fmt.Printf("s的数据类型为%T s=%q\n",s,s)

f := 3.14

sf := fmt.Sprintf("%.2f", f) // 将float64转换为带两位小数的string

fmt.Println(sf, "is a string")

fmt.Printf("sf的数据类型为%T sf=%q\n",sf,sf)

c := 'A'

sc := fmt.Sprintf("%c", c) // 将rune(在Go中char实际上是rune类型)转换为string

fmt.Println(sc, "is a string")

fmt.Printf("sc的数据类型为%T sc=%q\n",sc,sc)

// 注意:bool类型通常不直接转换为string,但可以通过fmt.Sprintf实现

b := true

sb := fmt.Sprintf("%t", b) // 将bool转换为string

fmt.Println(sb, "is a string")

fmt.Printf("sb的数据类型为%T sb=%q\n",sb,sb)

}

使用strconv

对于整数和浮点数,strconv包提供了Itoa(int to ASCII)和FormatFloat等函数,但请注意Itoa只适用于int类型。对于其他整数类型(如int64),你可能需要使用FormatInt

package main

import (

"fmt"

"strconv"

)

func main() {

i := 123

s := strconv.Itoa(i) // 将int转换为string

fmt.Println(s, "is a string")

i64 := int64(1234567890)

s64 := strconv.FormatInt(i64, 10) // 将int64转换为string,10表示十进制

fmt.Println(s64, "is a string")

// 注意:对于float64,strconv.FormatFloat是更通用的选择

f := 3.14

sf := strconv.FormatFloat(f, 'f', -1, 64) // 'f'表示固定点数表示,-1表示精度(自动),64表示float64

fmt.Println(sf, "is a string")

}

string转基本数据类型

使用strconv

strconv包提供了ParseIntParseUintParseFloatParseBool等函数,用于将string转换为相应的基本数据类型。

package main

import (

"fmt"

"strconv"

)

func main() {

s := "123"

i, err := strconv.Atoi(s) // Atoi是ParseInt的简便封装,只处理int类型

if err != nil {

fmt.Println("Error converting string to int:", err)

}

fmt.Println(i, "is an int")

s64 := "1234567890"

i64, err := strconv.ParseInt(s64, 10, 64) // 第二个参数是基数(10表示十进制),第三个参数是bitSize

if err != nil {

fmt.Println("Error converting string to int64:", err)

}

fmt.Println(i64, "is an int64")

sf := "3.14"

f, err := strconv.ParseFloat(sf, 64) // 第二个参数是bitSize(32或64)

if err != nil {

fmt.Println("Error converting string to float64:", err)

}

fmt.Println(f, "is a float64")

sb := "true"

b, err := strconv.ParseBool(sb)

if err != nil {

fmt.Println("Error converting string to bool:", err)

}

fmt.Println(b, "is a bool")

}

//在将 String 类型转成 基本数据类型时,要确保 String 类型能够转成有效的数据,比如 我们可以把 "123" , 转成一个整数,但是不能把 "hello" 转成一个整数,如果这样做,Golang 直接将其转成 0 , 其它类型也是一样的道理. float => 0, bool => false

对于'%'的解释:

在Go语言的fmt.Sprintf函数中,%后跟的字母称为格式说明符(format specifier),它们决定了如何将后续的值(参数)格式化为字符串。每个格式说明符都对应一种不同的数据类型或值的表示方式。在你给出的例子中,%d%.2f%c%t分别代表了不同的数据类型或值的格式化方式:

  1. %d:用于整数(intint8int16int32int64 等)的十进制表示。它会把整数转换成其十进制形式的字符串。

  2. %.2f:用于浮点数(float32float64)的格式化表示,其中.2指定了小数点后的位数,即保留两位小数。它会把浮点数转换成具有两位小数的字符串。

  3. %c:用于字符(在Go中实际上是rune类型,用于表示Unicode字符)的格式化。它会把rune类型的值转换成对应的单个字符的字符串。

  4. %t:用于布尔值(bool)的格式化。它会把布尔值转换成字符串"true"或"false"。

这些格式说明符允许开发者在将值转换为字符串时,指定值的表示形式,比如整数是否以十六进制显示、浮点数保留多少位小数、字符是否应该直接显示等。这种灵活性是fmt包提供的重要特性之一,使得在输出格式化字符串时非常方便。

fmt.Printffmt.Sprintf等函数中,这些格式说明符都是通用的,可以用于任何需要格式化输出的场景。不过,需要注意的是,格式说明符必须与它后面的参数类型相匹配,否则可能会导致运行时错误或不符合预期的输出。例如,你尝试用%d来格式化一个浮点数,结果可能不是你想要的。

指针变量

想象一下,每个变量在计算机的内存中都有一个独特的"家"(地址)。指针就像是那个"家"的门牌号,但它不是直接存储数据,而是存储了数据所在的"家"的地址。通过指针,我们可以直接找到并操作那个"家"里的数据,而不需要复制数据本身。

指针变量的声明和初始化

在Go语言中,我们可以通过在变量类型前加上*符号来声明一个指针变量。例如,var ptr *int声明了一个名为ptr的指针变量,它可以指向一个int类型的变量。

初始化指针变量通常有两种方式:

  1. 使用&操作符&操作符可以获取一个变量的地址,并将这个地址赋值给指针变量。例如,var a int = 10; ptr = &a;这样,ptr就指向了a的地址。

  2. 使用new函数new函数是Go语言内建的一个函数,用于为指定类型分配内存,并返回指向这块内存的指针。例如,ptr = new(int)会为int类型分配内存,并将返回的指针赋值给ptr。

指针的使用

指针的使用主要涉及两个操作符:&(取地址)和*(解引用,即根据地址取值)。

  • 取地址 :如上所述,使用&操作符可以获取变量的地址。

  • 解引用 :使用*操作符可以获取指针所指向的变量的值。例如,如果ptr指向了a的地址,那么*ptr就等价于a的值。

例子:

package main

import(

"fmt"

)

func main(){

var a int =123

var str string = "forword"

fmt.Printf("a: %p, str:%p",&a,&str)

}

a: 0xc00000a0e8, str:0xc000026070

内存地址是0x十六进制前缀的一组数据
var ptr *int =&b

fmt.Printf("ptr地址=%v\n",&ptr)

fmt.Printf("b的地址=%v\n",ptr)

fmt.Printf("ptr值=%v\n",*ptr)

b的地址为 0xc00000a108

ptr地址=0xc000058030

ptr=0xc00000a108

ptr值=1234

指针的重要性

指针在Go语言中非常重要,原因有以下几点:

  1. 提高效率:通过指针,我们可以直接操作内存中的数据,避免了数据复制的开销,这在处理大型数据结构时尤为重要。

  2. 实现引用传递:在Go语言中,函数的参数传递默认是值传递。但如果我们传递的是指针,那么在函数内部对指针所指向的变量的修改会影响到原始变量。

  3. 实现动态数据结构:如切片(slice)、映射(map)和通道(channel)等Go语言中的高级数据结构,在底层都是通过指针来实现的。

注意事项

虽然指针很强大,但也需要谨慎使用,以避免出现以下问题:

  • 空指针解引用 :如果指针没有被正确初始化(即它指向的是nil),那么尝试解引用它将导致运行时错误。

  • 悬挂指针:如果指针指向的内存被释放或重新分配,但指针本身没有被更新,那么这个指针就变成了悬挂指针,解引用它也可能导致错误。

  • 内存泄漏:如果不再需要某个指针指向的内存,但没有显式地释放它(Go语言有垃圾回收机制,但在某些情况下仍需注意),就可能导致内存泄漏。

相关推荐
C-SDN花园GGbond44 分钟前
【探索数据结构与算法】插入排序:原理、实现与分析(图文详解)
c语言·开发语言·数据结构·排序算法
罗政2 小时前
[附源码]超简洁个人博客网站搭建+SpringBoot+Vue前后端分离
vue.js·spring boot·后端
迷迭所归处2 小时前
C++ —— 关于vector
开发语言·c++·算法
架构文摘JGWZ2 小时前
Java 23 的12 个新特性!!
java·开发语言·学习
leon6252 小时前
优化算法(一)—遗传算法(Genetic Algorithm)附MATLAB程序
开发语言·算法·matlab
拾光师3 小时前
spring获取当前request
java·后端·spring
锦亦之22333 小时前
QT+OSG+OSG-earth如何在窗口显示一个地球
开发语言·qt
我是苏苏3 小时前
Web开发:ABP框架2——入门级别的增删改查Demo
java·开发语言
姜太公钓鲸2333 小时前
c++ static(详解)
开发语言·c++
菜菜想进步3 小时前
内存管理(C++版)
c语言·开发语言·c++