ホームページ  >  記事  >  バックエンド開発  >  Go 言語の比較 C++ 参照パラメータの受け渡し

Go 言語の比較 C++ 参照パラメータの受け渡し

巴扎黑
巴扎黑オリジナル
2017-09-02 11:16:131436ブラウズ

この記事では、Go に参照によるパラメータ受け渡しがあるかどうか (C++ と比較して) を主に紹介します。必要な場合は、

C++ の 3 つのパラメータ受け渡しメソッドを参照してください。パラメーターを渡す方法。関数の仮パラメーターは実際のパラメーターのコピーです。関数内で仮パラメーターを変更しても、関数の外部の仮パラメーターには影響しません。一般に、値の受け渡しは、呼び出し元に影響を与えずに関数内のパラメーターを変更する場合に使用されます。 ポインタ渡し

仮引数は、その名の通り、実引数のアドレスを指すポインタであり、関数内で仮引数が指す内容を操作すると、実引数そのものが変更されます。 。

参照渡し

C++ では、参照は変数のエイリアスであり、実際には同じものであり、メモリ内の同じアドレスにも存在します。言い換えれば、参照が操作される場合はどこでも、参照される変数はまったく直接操作されます。

以下のデモを見てください:

#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でのパラメータの受け渡し



以上、3つのパラメータの受け渡し方法を紹介しました。 C++、値の受け渡しとポインターの受け渡しは簡単だと理解していますが、Go にもこれらのパラメーターの受け渡しメソッドはありますか?これは議論を引き起こしましたが、C++ の参照受け渡しの概念と比較すると、Go には参照受け渡しのメソッドが存在しないと言えます。なぜこんなことを言うのかというと、Go には変数参照の概念がないからです。ただし、Go には参照型があり、これについては後で説明します。

まず Go で値とポインタを渡す例を見てみましょう:

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 では、参照型にはスライス、辞書、チャネルなどが含まれます。スライスを例に挙げます。スライスを渡すことは参照ですか?

例:

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 が変更されたかどうかを確認する必要があります。まず、スライスの性質を理解する必要があります。

スライスは配列フラグメントの説明です。これには、配列へのポインタ、フラグメントの長さが含まれます。

言い換えると、上で出力したものはスライスそのものではなく、スライスが指す配列です。別の例として、スライスが変更されたかどうかを確認します。

  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

この結果は、呼び出しの前後でスライスが変化していないことを示しています。前の例のいわゆる「変更」は、実際には、スライス内の配列へのポインタが指す配列の要素が変更されたことを意味します。この文は少しぎこちないかもしれませんが、実際にはそうです。参照型のパラメーター受け渡しが参照渡しではないことをもう一度証明します。

スライスとは配列の断片の説明です。これには、配列へのポインタとフラグメントの長さが含まれています。興味がある場合は、この記事を参照してください: http://www.jb51.net/kf/201604/499045.html。スライシングのメモリ モデルについて学びます。

まとめ

概要は非常にシンプルですが、言語も本質を見抜くには現象を見抜く必要があります。この記事には、覚えておくべき結論もあります:

Go には参照渡しはありません。

以上がGo 言語の比較 C++ 参照パラメータの受け渡しの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。