Go 语言为什么建议 append 追加新元素使用原切片变量接收返回值?

介绍

在 Go 语言中,切片类型比较常用,将新元素追加到切片也比较常见,因此 Go 语言提供一个内置函数 append,该函数可以非常方便实现此功能。

虽然 Go 语言内置函数 append 使用非常方便,但是使用不当会不小心掉入一些“坑”。

本文我们介绍一下 Go 语言为什么建议 append 追加新元素使用原切片变量接收返回值?

append 的“坑”

我们先看一段示例代码:

func main() {
 a := make([]int, 0, 5)
 a = append(a, 1)
 b := append(a, 2)
 c := append(a, 3)
 fmt.Printf("v=%v || p=%p\n", a, &a) // v=[1] || p=0xc00000c060
 fmt.Printf("v=%v || p=%p\n", b, &b) // v=[1 3] || p=0xc00000c080
 fmt.Printf("v=%v || p=%p\n", c, &c) // v=[1 3] || p=0xc00000c0a0
}
  1. 阅读上面这段代码,我们定义一个长度为 0,容量为 5 的 int 类型的切片 a。

  2. 首先,我们使用 Go 语言内置函数 append 追加一个元素 1 到切片 a 中。

  3. 然后,我们使用 Go 语言内置函数 append 追加一个元素 2 到切片 a 中。

  4. 最后,我们使用 Go 语言内置函数 append 追加一个元素 3 到切片 a 中。

但是,我们在输出结果中发现,b 的输出结果不是 [1 2],c 的输出结果不是 [1 2 3],b 和 c 的实际输出结果相同,都是 [1 3]。为什么呢?我们接着往下看 Part 03 的内容。

append 的原理

Go 语言内置函数 append 第一个入参是切片类型的变量,而切片本身是一个 struct 结构,参数传递时会发生值拷贝。

Go 语言 slice 源码如下:

type slice struct {
 array unsafe.Pointer
 len   int
 cap   int
}

因为 Go 语言内置函数 append 参数是值传递,所以 append 函数在追加新元素到切片时,append 会生成一个新切片,并且将原切片的值拷贝到新切片。

  1. 在 Part 02 示例代码中,我们三次使用 append 参数追加新元素到切片 a 的操作,接收返回值的变量都不同。

  2. 第二次操作时,因为 append 生成一个新切片,将原切片 a 的值拷贝到新切片,并且将新元素在原切片a[len(a)] 长度的位置开始追加,使用变量 b 接收 append 返回值 [1 2],所以变量 b 的值是 [1 2]。

  3. 第三次操作时,同样 append 生成一个新切片,将原切片 a 的值拷贝到新切片,并且将新元素在原切片a[len(a)] 长度的位置开始追加,使用变量 c 接收 append 返回值 [1 3],所以变量 c 的值是 [1 3]。

  4. 但是,因为三个切片的底层数组相同,Go 内置函数 append 会在原切片长度的位置开始追加新元素,所以第三次操作时,把第二次操作时得到的变量 b 的最后一个元素覆盖了。

阅读到这里,相信聪明的读者朋友们已经明白 Part 02 示例代码为什么实际输出结果和预想的输出结果不同了吧。

总结

本文我们介绍 Go 语言中使用内置函数 append 追加新元素的一个“坑”,建议读者朋友们使用原切片变量接收返回值。

| 原文 https://mp.weixin.qq.com/s/jGTslWJF4bDXmynISI9btA

本文由 mdnice 多平台发布

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
以下是一个简单的使用libcurl访问百度网站的示例,并使用变量接收返回并统计请求时间: ```c++ #include <iostream> #include <string> #include <curl/curl.h> #include <chrono> using namespace std::chrono; // 回调函数,处理返回的数据 static size_t write_callback(char* ptr, size_t size, size_t nmemb, std::string* data) { data->append(ptr, size * nmemb); return size * nmemb; } int main() { // 初始化libcurl CURL* curl = curl_easy_init(); if (!curl) { std::cerr << "Failed to initialize libcurl" << std::endl; return 1; } // 设置请求的URL curl_easy_setopt(curl, CURLOPT_URL, "http://www.baidu.com"); // 创建一个string来保存返回的数据 std::string response; // 设置回调函数,处理返回的数据 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response); // 发送请求并计时 auto start = steady_clock::now(); CURLcode res = curl_easy_perform(curl); auto end = steady_clock::now(); auto duration = duration_cast<milliseconds>(end - start); // 检查请求是否成功 if (res != CURLE_OK) { std::cerr << "Failed to send request: " << curl_easy_strerror(res) << std::endl; curl_easy_cleanup(curl); return 1; } // 输出返回的数据和请求时间 std::cout << "Response: " << response << std::endl; std::cout << "Request time: " << duration.count() << "ms" << std::endl; // 清理并释放资源 curl_easy_cleanup(curl); return 0; } ``` 该示例中使用了C++11中的chrono库来计时,使用了CURLcode枚举类型来检查请求是否成功。运行该程序,将输出百度网站返回的HTML代码和请求所花费的时间。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

a...Z

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

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

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

打赏作者

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

抵扣说明:

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

余额充值