넘어가는 것은 값의 사본이다
Esc

    넘어가는 것은 값의 사본이다

    –C#기초

    메서드를 부를 때 괄호에 값을 넣습니다. 그럼 그 값이 어떻게 넘어갈까요.

    void AddTen(int n)
    {
        n = n + 10;
        Console.WriteLine(n);
    }
    
    int score = 50;
    AddTen(score);
    Console.WriteLine(score);

    AddTen 안에서는 60 이 나옵니다. 그럼 마지막 줄은 무엇이 나올까요.

    50 입니다.

    부르는 쪽 이름과 받는 쪽 이름은 남남이다

    먼저 말을 정리하고 갑니다.

    • 정의에 적는 것이 매개변수입니다. 위에서 int n 입니다.
    • 호출할 때 실제로 넣는 것이 인수입니다. 위에서 score 입니다.

    이름이 달라도 됩니다. 같아도 됩니다. 서로 아무 상관이 없기 때문입니다. 매개변수 이름은 메서드 안에서만 통합니다. 밖에서는 무슨 이름이든 상관없습니다.

    int score = 50;
    int point = 30;
    
    AddTen(score);
    AddTen(point);
    AddTen(80);        // 이름 없는 값을 그대로 넣어도 됩니다

    AddTen 은 받은 것이 score 인지 point 인지 80 인지 모릅니다. 값만 받습니다.

    값이 복사되어 들어간다

    앞에서 변수는 값을 담는 자리라고 했습니다. 메서드를 부를 때 일어나는 일은 그 값을 새 자리에 옮겨 적는 것입니다.

    자리가 두 개입니다. 밖의 score 와 안의 n 은 다른 자리입니다. n 을 고쳐도 score 는 모릅니다.

    종이에 적은 숫자를 불러 주고 상대가 자기 종이에 받아 적은 것과 같습니다. 상대가 자기 종이의 숫자를 고쳐도 내 종이는 그대로입니다.

    그래서 값을 바꾸려면 돌려받는다

    밖의 값을 바꾸고 싶으면 돌려받아서 다시 담습니다.

    int AddTen(int n)
    {
        return n + 10;
    }
    
    int score = 50;
    score = AddTen(score);      // 돌려받은 것을 다시 담습니다
    Console.WriteLine(score);   // 60

    앞에서 문자열 메서드가 이랬습니다. s.ToUpper() 는 아무 일도 안 일어나고 s = s.ToUpper() 라야 바뀌었습니다.

    이유가 이제 보입니다. 특별한 규칙이 아니라 메서드가 원래 그렇게 동작하기 때문입니다. 받은 것을 고쳐도 부른 쪽에는 안 보이니, 결과를 돌려주는 것 말고는 알릴 방법이 없습니다.

    안에서 마음대로 써도 된다

    사본이라는 성질에는 좋은 점도 있습니다. 매개변수를 안에서 자유롭게 고쳐 써도 밖에 영향이 없습니다.

    int Countdown(int n)
    {
        int total = 0;
    
        while (n > 0)
        {
            total += n;
            n--;              // 매개변수를 직접 줄여도 됩니다
        }
    
        return total;
    }

    n 을 반복문 변수처럼 써 버렸습니다. 그래도 부른 쪽 값은 멀쩡합니다. 따로 변수를 만들어 옮겨 담을 필요가 없습니다.

    다만 읽기에는 헷갈릴 수 있습니다. 매개변수는 “받은 값” 이라는 뜻이 강해서, 중간에 다른 뜻으로 바뀌면 읽는 사람이 되짚어야 합니다. 길어지는 메서드에서는 새 변수를 만드는 편이 낫습니다.

    목록을 넘기면 결과가 다르다

    여기까지는 int 하나를 넘겼습니다. 그런데 List 나 배열을 넘기면 이야기가 달라집니다.

    void AddItem(List<int> list)
    {
        list.Add(99);
    }
    
    List<int> nums = new List<int> { 1, 2 };
    AddItem(nums);
    Console.WriteLine(nums.Count);    // 3

    이번에는 밖이 바뀝니다. 앞에서 본 것과 반대입니다.

    지금 단계에서는 그런 경우가 있다는 것만 알아 두면 됩니다. 이유를 제대로 말하려면 List 를 담은 변수 안에 실제로 무엇이 들어 있는지를 봐야 하는데, 그건 클래스와 객체를 다룰 때 정리합니다.

    당장 기억할 것은 하나입니다. 숫자나 글자 하나를 넘겼다면 안에서 무엇을 하든 밖은 그대로입니다. 바뀌길 원하면 return 으로 돌려받습니다.

    정리

    • 정의에 적는 것이 매개변수, 호출할 때 넣는 것이 인수입니다.
    • 매개변수 이름은 메서드 안에서만 통합니다. 밖의 변수 이름과 상관없습니다.
    • 넘어가는 것은 값의 사본입니다. 안과 밖은 다른 자리입니다.
    • 그래서 안에서 매개변수를 고쳐도 밖은 그대로입니다.
    • 밖의 값을 바꾸려면 return 으로 돌려주고 다시 담습니다.
    • 매개변수를 안에서 마음대로 써도 안전합니다. 다만 읽기에 헷갈릴 수 있습니다.
    • List 나 배열처럼 여러 개를 담는 것을 넘기면 결과가 다릅니다.