- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章Go语言到底有没有引用传参(对比 C++ )由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
C++ 中三种参数传递方式 。
值传递:
最常见的一种传参方式,函数的形参是实参的拷贝,函数中改变形参不会影响到函数外部的形参。一般是函数内部修改参数而又不希望影响到调用者的时候会采用值传递.
指针传递 。
形参是指向实参地址的一个指针,顾名思义,在函数中对形参指向的内容操作,实参本身会被修改.
引用传递 。
在 C++ 中,引用是变量的别名,实际上是同一个东西,在内存中也存在同一个地址。换句话说,不管在哪里对引用操作,都相当直接操作被引用的变量.
下面看 demo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
#include <iostream>
//值传递
void
func1(
int
a) {
std::cout <<
"值传递,变量地址:"
<< &a <<
", 变量值:"
<< a << std::endl;
a ++ ;
}
//指针传递
void
func2 (
int
* a) {
std::cout <<
"指针传递,变量地址:"
<< a <<
", 变量值:"
<< *a << std::endl;
*a = *a + 1;
}
//引用传递
void
func3 (
int
& a) {
std::cout <<
"指针传递,变量地址:"
<< &a <<
", 变量值:"
<< a << std::endl;
a ++;
}
int
main() {
int
a = 5;
std::cout <<
"变量实际地址:"
<< &a <<
", 变量值:"
<< a << std::endl;
func1(a);
std::cout <<
"值传递操作后,变量值:"
<< a << std::endl;
std::cout <<
"变量实际地址:"
<< &a <<
", 变量值:"
<< a << std::endl;
func2(&a);
std::cout <<
"指针传递操作后,变量值:"
<< a << std::endl;
std::cout <<
"变量实际地址:"
<< &a <<
", 变量值:"
<< a << std::endl;
func3(a);
std::cout <<
"引用传递操作后,变量值:"
<< a << std::endl;
return
0;
}
|
输出结果如下:
变量实际地址:0x28feac, 变量值:5 值传递,变量地址:0x28fe90, 变量值:5 值传递操作后,变量值:5 变量实际地址:0x28feac, 变量值:5 指针传递,变量地址:0x28feac, 变量值:5 指针传递操作后,变量值:6 变量实际地址:0x28feac, 变量值:6 指针传递,变量地址:0x28feac, 变量值:6 引用传递操作后,变量值:7 。
Go 中的参数传递 。
上面介绍了 C++ 的三种参数传递方式,值传递和指针传递容易理解,那么 Go 是不是也有这些传参方式呢?这引起过争论,但是对比 C++ 的引用传递的概念,我们可以说,Go 没有引用传递方式。为什么这么说,因为 Go 没有变量的引用这一概念。但是 Go 有引用类型,这个稍后再解释.
先看一个 Go 传值和传指针的例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
package main
import (
"fmt"
)
func main() {
a := 1
fmt.Println(
"变量实际地址:"
, &a,
"变量值:"
, a)
func1 (a)
fmt.Println(
"值传递操作后,变量值:"
, a)
fmt.Println(
"变量实际地址:"
, &a,
"变量值:"
, a)
func2(&a)
fmt.Println(
"指针传递操作后,变量值:"
, a)
}
//值传递
func func1 (a
int
) {
a++
fmt.Println(
"值传递,变量地址:"
, &a,
"变量值:"
, a)
}
//指针传递
func func2 (a *
int
) {
*a = *a + 1
fmt.Println(
"指针传递,变量地址:"
, a,
"变量值:"
, *a)
}
|
输出结果如下:
变量实际地址: 0xc04203c1d0 变量值: 1 值传递,变量地址: 0xc04203c210 变量值: 2 值传递操作后,变量值: 1 变量实际地址: 0xc04203c1d0 变量值: 1 指针传递,变量地址: 0xc04203c1d0 变量值: 2 指针传递操作后,变量值: 2 可以看出,Go 基本类型的值传递和指针传递和 C++ 并没有什么不同,但是它没有变量的引用这一概念。那 Go 的引用类型怎么理解呢?
Go 的引用类型 。
在 Go 中,引用类型包含切片、字典、通道等。以切片为例,传切片是传引用么?
举个例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
package main
import (
"fmt"
)
func main() {
m1 := make([]string, 1)
m1[0] =
"test"
fmt.Println(
"调用 func1 前 m1 值:"
, m1)
func1(m1)
fmt.Println(
"调用 func1 后 m1 值:"
, m1)
}
func func1 (a []string) {
a[0] =
"val1"
fmt.Println(
"func1中:"
, a)
}
|
输出结果如下:
调用 func1 前 m1 值: [test] 。
func1中: [val1] 。
调用 func1 后 m1 值: [val1] 。
函数中对切片做出的修改影响了实际参数的值。是不是说这事引用传递?
其实并不是,要回答这个问题,首先得搞清楚调用函数切片 m1 到底有没有改变。首先我们要认清楚切片的本质.
一个切片是一个数组片段的描述。它包含了指向数组的指针,片段的长度.
也就是说,上面我们打印的并不是切片本身,而是切片指向的数组。再举个例子,验证一下切片到底有没有发生变化.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
package main
import (
"fmt"
)
func main() {
m1 := make([]string, 1)
m1[0] =
"test"
fmt.Println(
"调用 func1 前 m1 值:"
, m1, cap(m1))
func1(m1)
fmt.Println(
"调用 func1 后 m1 值:"
, m1, cap(m1))
}
func func1 (a []string) {
a = append(a,
"val1"
)
fmt.Println(
"func1中:"
, a, cap(a))
}
|
输出结果如下:
调用 func1 前 m1 值: [test] 1 。
func1中: [test val1] 2 。
调用 func1 后 m1 值: [test] 1 。
这个结果说明,调用前后切片并没有发生变化。之前例子中所谓的“变化”其实是切片中指向数组的指针指向的数组的元素发生了变化,这句话可能比较拗口,但实际如此。再次证明,引用类型的传参不是 pass-by-reference .
想透彻的了解 一个切片是一个数组片段的描述。它包含了指向数组的指针,片段的长度这句话。学习一下切片的内存模型.
总结 。
总结很简单,语言也需要透过现象看本质。还有本文的结论需要记住:
There is no pass-by-reference in Go. 。
以上所述是小编给大家介绍的Go语言到底有没有引用传参(对比 C++ ),希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我网站的支持! 。
原文链接:http://www.cnblogs.com/artong0416/p/7461756.html 。
最后此篇关于Go语言到底有没有引用传参(对比 C++ )的文章就讲到这里了,如果你想了解更多关于Go语言到底有没有引用传参(对比 C++ )的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我是一名优秀的程序员,十分优秀!