• 技术文章 >后端开发 >Golang

    Golang字符串类型怎么就不能修改?

    藏色散人藏色散人2022-11-21 20:36:28转载194
    本文由golang教程栏目给大家介绍关于golang中的字符串类型修改的问题,可能你很纳闷,日常开发中我们对字符串进行修改也是很正常的,为什么会听说 Go 中的字符串不能进行修改呢?下面就结合实例详细讲解,希望对需要的朋友有所帮助!

    在接触 Go 这么语言,可能你经常会听到这样一句话。对于字符串不能修改,可能你很纳闷,日常开发中我们对字符串进行修改也是很正常的,为什么又说 Go 中的字符串不能进行修改呢?

    本文就来通过实际案例给大家演示,为什么 Go 中的字符串不能进行修改。

    在演示这个问题之前,我们先对字符串类型的基础知识做个大致的演示,这样便于大家对问题的进一步了解。

    字符串定义

    字符串是一种用来表示字符的数据类型。在使用时,使用” “将字符内容包含起来。例如下面的形式:

    package main
    import "fmt"
    func main() {
        var str string = "Hello World!"
    }

    在 Go 中,字符串通常有三种定义方式:

    // 第一种(全量定义)
    var 变量名称 string = "字符串内容"
    // 类型推导
    var 变量名称 = "字符串内容"
    // 短标记(只适用于局部变量)
    变量名称 := "字符串内容"

    字符串的定义,其实也可以通过字节的方式。这里罗列的方式是最为常见的方式。

    字符串的组成

    Go 中的字符串符合 Unicode 标准,并且采用 UTF-8 编码。字符串底层其实也是由 byte 组成 (后面会仔细讲解)。通过下面的示例,打印查看具体的字节内容:

    s := "Hello World!"
    for _, v := range s {
        fmt.Print(v)
        fmt.Print("\t")
    }
    // 72 101 108 108 111 32 87 111 114 108 100 33

    上面代码打印的内容,就是每一个字符所表示的字节码。

    字符串不能修改

    通过上面的大致演示,我们对字符串有一个基本的了解。对于字符串不能修改,可能你很纳闷,日常开发中我们对字符串进行重新赋值也是很正常的,为什么又说 Go 中的字符串不能进行修改呢?

    其实这里要纠正这个说话,对于字符串修改并不等价于重新赋值。开发中常用的方式,其实是一种重新赋值的概念。

    str := "Hello World!"
    // 重新赋值
    str = "Hello Go!"
    // 字符串修改
    str[0] = "I"

    通常听到的不能修改,其实就是指的上面代码的第二种方式。并且通过这种方式修改会报错::cannot assign to s [0] (value of type byte)

    回归正题,为什么 Go 中的字符串不能通过下标的方式来进行修改呢?

    这是因为 Go中的字符串的数据结构体是由一个指针和长度组成的结构体,该指针指向的一个切片才是真正的字符串值。Go 中源码有这样一段定义:

    type stringStruct struct {
        str unsafe.Pointer // 指向一个byte类型的切片指针
        len int // 字符串的长度
    }

    676049d08b06350f904c5b58ca17e16.jpg

    php入门到就业线上直播课:进入学习

    正是因为底层是一个 [] byte 类型的切片,当我们使用下标的方式去修改值,这时候将一个字符内容赋值给 byte 类型,肯定是不允许的。但是我们可以通过下标的方式去访问对应的 byte 值。

    fmt.Println(s[0]) // output:72

    那我们要想通过下标的方式去修改值该怎么办呢?这时候,就需要通过切片的方式来定义,然后在转成字符串。

    package main
    import (  
        "fmt"
    )
    func main() {  
         s1 := []byte{72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33}
        fmt.Println(string(s1))
        // 将"H"修改为l
        s1[0] = 108
        fmt.Println(string(s1))
    }
    // output:
    Hello World!
    lello World!

    字符串的赋值

    上面分析了为什么字符串不能使用下标去赋值,回过来解答一下日常开发中的赋值方式。

    package main
    import (  
        "fmt"
    )
    func main() {
        // 声明一个字符串,并给与初始值
        s := "Hello World!"
        // 对变量 s 进行重新赋值
        s := "Hello Go!"
    }

    那为什么这种场景下又可以给字符串重新赋值呢?

    这是因为,在 Go 的底层其实是新创建了一个 [] byte {} 类型的切片,将变量 s 中的指针指向了新的内存空间地址 (也就是这里的 Hello Go!)。原有的 Hello World! 内存空间会随着垃圾回收机制被回收掉。

    e86d7912d65ad4968cc66ec1e92dc4b.jpg

    为什么这么设计

    可能大家都会考虑到,为什么一个普通的字符串要设计这么复杂,还需要使用指针。暂时没找到官方文档的说明,

    个人猜想,当遇到一个非常长的字符时,这样做使得 string 变得非常轻量,可以很方便的进行传递而不用担心内存拷贝。虽然在 Go 中,不管是引用类型还是值类型参数传递都是值传递。但指针明显比值传递更节省内存。

    以上就是Golang字符串类型怎么就不能修改?的详细内容,更多请关注php中文网其它相关文章!

    声明:本文转载于:learnku,如有侵犯,请联系admin@php.cn删除

    前端(VUE)零基础到就业课程:点击学习

    清晰的学习路线+老师随时辅导答疑

    自己动手写 PHP MVC 框架:点击学习

    快速了解MVC架构、了解框架底层运行原理

    专题推荐:字符串 Golang
    上一篇:聊聊Golang自带的HttpClient超时机制 下一篇:自己动手写 PHP MVC 框架(40节精讲/巨细/新人进阶必看)

    相关文章推荐

    • ❤️‍🔥共22门课程,总价3725元,会员免费学• ❤️‍🔥接口自动化测试不想写代码?• 一文详解Golang中的位操作• 为速度而生:PHP 与Golang 的合体 —— RoadRunner• 一文详解golang如何实现ssh相关操作• 详解Golang中的Struct(结构体)• 聊聊Golang自带的HttpClient超时机制
    1/1

    PHP中文网