0

0

Go语言中临时值地址的获取与*string的最佳实践

DDD

DDD

发布时间:2025-09-02 22:53:01

|

483人浏览过

|

来源于php中文网

原创

Go语言中临时值地址的获取与*string的最佳实践

"Go语言中,不能直接获取函数返回的临时值的地址。要获取其指针,需先将其赋值给一个变量。本文将详细阐述这一机制,并深入探讨*string类型的使用场景及其与string类型的区别,强调在大多数情况下,直接使用string类型更为简洁高效。"

理解Go语言中地址操作符的行为

go语言中,地址操作符&用于获取变量的内存地址,并返回一个指向该变量的指针。然而,并非所有表达式的值都具有可寻址性(addressability)。函数调用的返回值、字面量(如"hello")、常量或复合表达式的结果通常是临时值,它们在内存中没有固定的“家”(home),因此不能直接对其使用&操作符。

考虑以下代码示例,它尝试直接获取函数a()返回值的地址:

package main

import "fmt"

func a() string {
    return "Hello, Go!"
}

func main() {
    // 尝试直接获取函数返回值的地址,这将导致编译错误
    // b *string = &a() // 编译错误: cannot take the address of a()
    fmt.Println("尝试直接获取临时值地址会失败。")
}

上述代码在编译时会产生错误:cannot take the address of a()。这是因为a()的返回值是一个临时的字符串值,它不关联到任何可寻址的内存位置。要成功获取其地址,我们需要先将其存储到一个变量中。

获取临时值地址的正确方法

要获取函数返回的临时值的地址,必须先将其赋值给一个变量。一旦值被赋给一个变量,该变量就拥有了明确的内存地址,从而变得可寻址。

以下是解决上述问题的惯用方法:

立即学习go语言免费学习笔记(深入)”;

package main

import "fmt"

func a() string {
    return "Hello, Go!"
}

func main() {
    // 正确的做法:先将临时值赋给一个变量
    tmp := a()
    b := &tmp // 现在可以成功获取变量tmp的地址

    fmt.Printf("变量tmp的值: %s\n", tmp)
    fmt.Printf("指针b指向的值: %s\n", *b)
    fmt.Printf("指针b的地址: %p\n", b)

    // 验证通过指针修改变量的值
    *b = "Goodbye, Go!"
    fmt.Printf("修改后变量tmp的值: %s\n", tmp)
    fmt.Printf("修改后指针b指向的值: %s\n", *b)
}

在这个例子中,a()的返回值"Hello, Go!"首先被赋给了局部变量tmp。此时,tmp成为一个可寻址的变量,我们可以安全地使用&tmp来获取其地址,并将其赋值给*string类型的指针b。后续通过*b对值进行修改,实际上是修改了tmp变量所存储的字符串。

*string 类型的使用场景与最佳实践

尽管可以获取string变量的地址并使用*string类型,但在Go语言中,*string的使用场景相对有限,并且在许多情况下,直接使用string类型更为推荐。

string 类型的特性

string在Go语言中是一个值类型,但其内部实现是一个结构体,包含一个指向底层字节数组的指针和一个表示长度的整数。这意味着string类型的值在传递时是高效的,它传递的是这个结构体的副本,而不是整个底层字节数组的副本。此外,Go中的string是不可变的,一旦创建,其内容就不能被修改。

阿里云-虚拟数字人
阿里云-虚拟数字人

阿里云-虚拟数字人是什么? ...

下载

何时考虑使用 *string

*string类型主要用于以下场景:

  1. 区分存在与缺失(nil vs. 空字符串): 在处理JSON、XML或数据库字段时,*string可以用来区分一个字段是明确地存在且为空字符串(""),还是根本不存在(nil)。这对于可选字段或需要精确表示“未设置”状态的场景非常有用。

    package main
    
    import (
        "encoding/json"
        "fmt"
    )
    
    type User struct {
        Name  string  `json:"name"`
        Email *string `json:"email,omitempty"` // email字段可能不存在或为空
    }
    
    func main() {
        // 示例1: Email字段缺失
        data1 := `{"name": "Alice"}`
        var user1 User
        json.Unmarshal([]byte(data1), &user1)
        fmt.Printf("User1: Name=%s, Email=%v (nil: %t)\n", user1.Name, user1.Email, user1.Email == nil)
    
        // 示例2: Email字段存在且为空字符串
        data2 := `{"name": "Bob", "email": ""}`
        var user2 User
        json.Unmarshal([]byte(data2), &user2)
        fmt.Printf("User2: Name=%s, Email=%v (nil: %t)\n", user2.Name, *user2.Email, user2.Email == nil)
    
        // 示例3: Email字段存在且有值
        data3 := `{"name": "Charlie", "email": "charlie@example.com"}`
        var user3 User
        json.Unmarshal([]byte(data3), &user3)
        fmt.Printf("User3: Name=%s, Email=%v (nil: %t)\n", user3.Name, *user3.Email, user3.Email == nil)
    }
  2. 函数需要修改调用者字符串变量: 如果一个函数需要修改调用者传入的string变量本身(即改变它指向的字符串),那么就需要传入*string。但这种情况在Go中相对少见,通常会选择返回一个新的string值。

何时不推荐使用 *string

在大多数情况下,直接使用string类型是更简洁、更Go语言惯用的做法,原因如下:

  • 传递效率: 如前所述,string本身是轻量级的,按值传递成本很低。使用*string并没有显著的性能优势。
  • 代码简洁性: 使用string类型避免了频繁的解引用操作(*someStringPtr),使代码更易读。
  • Go的哲学: Go推崇通过值传递来简化并发编程,减少共享状态。如果需要修改,通常是返回一个新的值。
  • 避免误解: 有些开发者可能误以为*string可以修改字符串内容。实际上,*string修改的是指针所指向的字符串变量,而不是字符串本身的值。由于string的不可变性,任何看似修改字符串的操作实际上都是创建了一个新的字符串,并让变量指向它。
package main

import "fmt"

func modifyStringValue(s string) {
    s = "Modified by value" // 仅修改了s的副本,原字符串不变
}

func modifyStringPointer(s *string) {
    *s = "Modified by pointer" // 修改了s指向的字符串变量
}

func main() {
    originalString := "Original"
    fmt.Printf("原始字符串: %s\n", originalString) // Original

    modifyStringValue(originalString)
    fmt.Printf("经过值传递函数修改后: %s\n", originalString) // Original (不变)

    modifyStringPointer(&originalString)
    fmt.Printf("经过指针传递函数修改后: %s\n", originalString) // Modified by pointer (改变)

    // 注意:即使通过指针修改,也是将新的字符串赋值给originalString变量,
    // 而不是修改了"Original"这个字符串字面量本身。
}

总结

在Go语言中,获取函数返回的临时值的地址需要一个中间步骤:先将其赋值给一个变量,再对该变量取地址。这是因为地址操作符&只能作用于可寻址的内存位置。

关于*string类型,虽然它有特定的应用场景,尤其是在处理可选字段和区分缺失值时,但在大多数情况下,直接使用string类型更为符合Go语言的惯例和效率原则。string类型因其轻量级的值传递和不可变性,使得代码更加清晰和健壮。开发者应根据具体需求,权衡string和*string的优劣,做出明智的选择。

相关专题

更多
json数据格式
json数据格式

JSON是一种轻量级的数据交换格式。本专题为大家带来json数据格式相关文章,帮助大家解决问题。

403

2023.08.07

json是什么
json是什么

JSON是一种轻量级的数据交换格式,具有简洁、易读、跨平台和语言的特点,JSON数据是通过键值对的方式进行组织,其中键是字符串,值可以是字符串、数值、布尔值、数组、对象或者null,在Web开发、数据交换和配置文件等方面得到广泛应用。本专题为大家提供json相关的文章、下载、课程内容,供大家免费下载体验。

529

2023.08.23

jquery怎么操作json
jquery怎么操作json

操作的方法有:1、“$.parseJSON(jsonString)”2、“$.getJSON(url, data, success)”;3、“$.each(obj, callback)”;4、“$.ajax()”。更多jquery怎么操作json的详细内容,可以访问本专题下面的文章。

307

2023.10.13

go语言处理json数据方法
go语言处理json数据方法

本专题整合了go语言中处理json数据方法,阅读专题下面的文章了解更多详细内容。

74

2025.09.10

string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

312

2023.08.02

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1436

2023.10.24

pdf怎么转换成xml格式
pdf怎么转换成xml格式

将 pdf 转换为 xml 的方法:1. 使用在线转换器;2. 使用桌面软件(如 adobe acrobat、itext);3. 使用命令行工具(如 pdftoxml)。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

1852

2024.04.01

xml怎么变成word
xml怎么变成word

步骤:1. 导入 xml 文件;2. 选择 xml 结构;3. 映射 xml 元素到 word 元素;4. 生成 word 文档。提示:确保 xml 文件结构良好,并预览 word 文档以验证转换是否成功。想了解更多xml的相关内容,可以阅读本专题下面的文章。

2080

2024.08.01

php源码安装教程大全
php源码安装教程大全

本专题整合了php源码安装教程,阅读专题下面的文章了解更多详细内容。

74

2025.12.31

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
WEB前端教程【HTML5+CSS3+JS】
WEB前端教程【HTML5+CSS3+JS】

共101课时 | 8.1万人学习

JS进阶与BootStrap学习
JS进阶与BootStrap学习

共39课时 | 3.1万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号