0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

CocoaAdvent Calendar 2018

Day 9

[cocoa][swift]え!それって参照渡し?

Posted at

はじめに

とても違和感を感じる用語がある。それは、『参照渡しだ』。
え!違うだろ?と感じていたが、いい機会なので、調べてみた。

引数

引数と呼ばれるものにどんな種類があるのか、まずは列挙してみる。

実引数

関数に渡す値。

sum(1, 2);

仮引数

関数が受け取った変数。

int sum(int a, int b)
{
    return a + b;
}

値渡し(call by value

値が渡される。

ポインタ渡し

渡す値がアドレスの値渡し。

参照渡し

変数渡し(call by variable)

変数そのものを渡す。

参照渡し(call by reference)

参照渡しで、内部でアドレス情報を渡す方法。

自分の理解では、初期のプログラミング言語ではローカル変数の実装が困難で、変数はグルーバル。なので、変数渡し。近年の高級言語でローカル変数が実現され、その流れで値渡しが用意されたのかなと思っている。

Pascal

Pascalでは,値渡し(call by value)と変数渡し(call by variable)が存在し、変数渡しは参照渡しに相当する。

そもそもは、変数渡しの実装方法に参照渡しがある。参照渡しは、変数に対する参照(アドレス情報)を渡す方法だ。

Inside Macintoshは、コードはPascalで記載されているが、それをC言語で利用する場合、varがついた変数渡しの引数は、C言語ではポインターと読み替えていた。

具体的には、Inside Macintoshで以下のようにPascalで説明されていたとする。

PROCEDURE GetPort(VAR port: GrafPtr);

これをC言語では、以下のように読み替える。

void GetPort (GrafPtr *port);

C言語

C言語の関数の引数は全て値渡し。K&Rでしっかりと説明されている。
ポインタでアドレスの値を渡すのを参照渡しと呼ぶのは間違いだ。

Java

Javaも全て値渡し。
ポインタ演算ができない、アドレス(参照)の値渡しが利用できるが、これを参照渡しと呼ぶのは、如何なものか。

0'RellyのJavaクイックリファレンスでは、Javaは配列とオブジェクトを参照を通じで扱うと説明されていた。また、参照渡しという言葉と混同しないようにと書かれていた。
参照型の値渡しが参照渡しと勘違いされるのは、仮引数の参照型の中身の値の変更が、実引数側に反映されるからだと思うが、参照先自体の変更ができない。これは、C言語で、引数で渡されたポインターが指す先の値は変えらるがアドレスは変えられない。変えたい場合は、ポインターのポインタを利用するしかないということから分かると思う。


static char a[] = "hello";
static char b[] = "world";
 
void set_b(char **handle)
{
    *handle = b;
}
 
in t main(int argc, char *argv[])
{
    char *ptr = a;
    printf("%s\n", ptr);
    set_b(&ptr);
    printf("%s\n", ptr);
    return EXIT_SUCCESS;
}

C++

値渡しに加え、本物の参照渡しが存在する。

void time_two(int& a)
{
    a *= 2;
}

また、C++11では右辺値参照・ムーブセマンティクスという所有者の移動が用意されている。

C#

二つの参照渡しの方法が用意されている。

ref

int initializeInMethod = 0;  // 初期化が必須
OutArgExample(initializeInMethod);
Console.WriteLine(initializeInMethod);
 
void OutArgExample(ref int number)
{
    number = 44;
}

out

int initializeInMethod;
OutArgExample(out initializeInMethod);
Console.WriteLine(initializeInMethod);
 
void OutArgExample(out int number)
{
    number = 44;  // 代入が必須
}

refは変数が渡されるので、初期化によって値が設定されていない変数はNGだ。

outは値を返すという意味から、初期化は必須でないか、関数内で値を必ず設定しないといけない。

Swift

値渡しだが、inoutキーワードをつけると値呼びの結果返し(call-by-value-result)となる。
C言語のポインターの場合と同様に、変数が参照型の場合、参照の値渡しにより値を変更できる。

class Demo {
    public var num = 0;
}
 
func set999(a: Demo) {
    a.num = 999;
}
 
let demo = Demo()
set999(demo)

値呼びの結果返しの例。

func set999(a: inout Int) {
    a =999
}
 
var num = 0
set999(&num)

少し複雑に感じるが、基本、C言語と同様と考えると成る程だ。

【関連情報】
Cocoa Advent Calendar 2018

Cocoa.swift 2019-01

Cocoa.swift

Cocoa勉強会 関東

Cocoa練習帳

Qiita

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?