Skip to main content

[探索 5 分鐘] 傳值 (pass by value) 與傳址 (pass by reference) 基礎觀念

 我們知道傳遞參數或 assign 變數時, 要注意是 pass by value, 還是 pass by reference。有時候, 語言切來切去或一時不察, 還是會犯下低級錯誤, 花費很多 debug 時間。

首先, 要知道哪一種傳遞方法之前, 必須先識別物件本身是屬於 reference type 還是 value type。比如 C# 語言, MSDN 這麼說。
與您熟悉的某些程式設計語言不同的是,C# 有兩種資料型別:實值和參考。如果應用程式的效能很重要,或是如果您對 C# 如何管理資料和記憶體有興趣,了解兩者之間的差別就很重要。當變數是以基本內建資料型別其中之一,或使用者定義的結構進行宣告時,此變數便是實值型別 (Value Type)。有一個例外是 String 資料型別,它屬於參考型別。
那基本內建資料型別有哪些呢 ? wiki 的分類整理。
Classic basic primitive types may include:
● Character (character, char);
● Integer (integer, int, short, long, byte) with a variety of precisions;
● Floating-point number (float, double, real, double precision);
● Fixed-point number (fixed) with a variety of precisions and a programmer-selected scale.
● Boolean, logical values true and false.
● Reference (also called a pointer or handle), a small value referring to another object's address in memory, possibly a much larger one.
注意用 may include 就是無法 100% 包括所有語言的原生型別, 畢竟還是有語言相關性的。常見的 value type 如 byte, sbyte, short, int, long, ushort, uint, ulong, float, double, bool, char, decimal; 反之, 就都是物件型式的 reference type。要特別注意的是 string, 他的長度不一並配置在連續的記憶體空間中, MDN 非常精簡的描述 string。
In any computer programming language, a string is a sequence of characters used to represent text.
In JavaScript, a String is one of the primitive values and the String object is a wrapper around a String primitive.
一分鐘再看這篇 C# - string文獻。總結 String 雖然是原生型別, 卻被歸類為 reference type, 然而操作行為卻又是 pass by value。
字串是「不可變的」;在建立物件之後,就無法變更字串物件的內容,雖然語法讓它看起來就像您可以這麼做一樣。 例如,當您撰寫此程式碼時,編譯器實際上會建立新的字串物件,以保存新序列的字元,並且會將新物件指派給 b。 字串 "h" 接著會適合進行記憶體回收。
注意 string 並不是唯一有這種特性的哦, 到 這裡 查看更多吧。補充一張根據 Six important .NET concepts: Stack, heap, value types, reference types, boxing, and unboxing 整理出來的型別分類大圖, 是不是更方便記憶了 (非常感謝) 。

程式筆記

C#

static List foo(List x)
{
    var local = x; // use new List(x) to copy
    local[0] = local[0] + 1;
    return local;
}

static void Main(string[] args)
{
    var d1 = new List { 1, 2, 3 };
    var d2 = foo(d1);
    Console.WriteLine(string.Join(" ", d1)); //[2,2,3]
    Console.WriteLine(string.Join(" ", d2)); //[2,2,3]
}

Python

def foo(x):
    local = x 'use x[:] to copy
    local[0] = local[0] + 1
    return local;

if __name__ == '__main__':
    d1 = [1, 2, 3]
    d2 = foo(d1)

    print(d1) '[2,2,3]
    print(d2) '[2,2,3]

Javascript

function foo(x){
    local = x; // use x.slice() to copy
    local[0] = local[0] + 1;
    return local;
}

var d1 = [1, 2, 3];
var d2 = foo(d1
console.log(d1); //[2,2,3]
console.log(d2); //[2,2,3]

php

待補

參考資料

  • https://msdn.microsoft.com/zh-tw/library/4d43ts61(v=vs.90).aspx
  • https://en.wikipedia.org/wiki/Primitive_data_type
  • https://docs.microsoft.com/zh-tw/dotnet/csharp/language-reference/keywords/string
  • https://coding.abel.nu/2014/09/net-and-equals/
  • https://www.codeproject.com/Articles/76153/Six-important-NET-concepts-Stack-heap-value-types#Stack%20and%20Heap

Comments