Go Language

[Go] #13-2 함수

Yeom's 2023. 1. 8. 17:35
728x90
반응형

전역변수와 지역변수

매개변수는 값 자체를 전달하는 방식(Pass by value)과 값의 주소를 전달하는 방식(Pass by reference)이 있다. 주소의 값을 참조하는 방식과 값을 복사해오는 방식의 개념에 대해서는 슬라이스와 맵 강의를 통해 먼저 설명했다. 하지만 이 개념을 매개변수의 적용하기 위해서는 지역변수와 전역변수의 개념에 대한 이해가 선행되어야 한다. 왜냐하면 매개변수에 전달하려는 변수가 어떤 유형의 변수이냐에 따라 사용 방법과 결과가 다르기 떄문이다.

지역변수와 전역변수는 선언되는 위치에 따라 그 유형이 결정된다. 지역변수는 중괄호({}) 안에서 선언된 변수를 말한다. 이렇게 선언된 지역변수는 선언된 지역 내에서만 유효하다. 전역변수는 특정 지역(중괄호) 밖에서 선언된 변수를 말한다. 이 변수는 지역과 관계없이 어느 곳에든 유효하다. 따라서 이 두 변수는 두 가지에 차이점이 있다.

  • 메모리에 존재하는 시간
  • 변수에 접글할 수 있는 범위

지역변수는 해당 지역에서 선언되는 순간 메모리가 생성되고 해당 지역을 벗어나면 자동으로 소멸된다. 하지만 전역변수는 코드가 시작되어 선언되는 순간 메모리가 생성되고 코드 전체가 끝날 때까지 메모리를 차지하고 있다. 이것이 바로 '메리에 존재하는 시간'에 대한 설명이다.

아래에는 지역변수에 대한 예시 코드가 있다.

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
30
package main
 
import "fmt"
 
func exampleFunc1() {
    var a int = 10 //지역변수 선언
    
    a++
    
    fmt.Println("exampleFunc1의 a는 ", a)
}
 
func exampleFunc2() {
    var b int = 20 //지역변수 선언
    var c int = 30 //지역변수 선언
 
    b++
    c++
 
    fmt.Println("b와 c는 ", b, c)
}
 
func main() {
    var a int = 28 //지역변수 선언
 
    exampleFunc1()
    exampleFunc2()
 
    fmt.Println("main의 a는", a)
}
cs

 

위 코드에서는 3개의 함수에서 총 4개의 변수가 선언되고 초기화된다. 지역변수는 해당 지역에서만 유효하다는 것을 보여주기 위해 일부러 main 함수 안의 a와 exampleFunc1 함수 안의 a의 변수 이름을 똑같이 설정했다.

우선 main 함수가 호출되면서 지역변수 a가 선언되고 메모리상에 a라는 이름의 변수가 할당되고 28로 초기화된다.

var a int = 28 다음 문장을 실행하면 바로 exampleFunc1  함수가 호출되고 지역변수 a를 선언하고 초기화를 했기 때문에 메모리 공간에는 추가로 변수 a가 할당되고 10으로 초기화된다. 하지만 이 상태는 main 함수가 종료된 상황이 아니기 때문에 main 함수 호출 시 할당된 변수 a도 메모리 공간에 함께 존재하게 된다. 위에 설명한 것 처럼 지역변수는 실행되고 있는 지역에서만 유효하므로 다른 지역의 변수의 변수명과 관계없다. 따라서 변수명이 같으면 가린다는 느낌이 든다.

그리고 exampleFunc1 의 코드를 차례로 실행하고 함수가 종료되면 exampleFunc1 함수에서 선언된 변수 a 는 메모리 공간에서 사라지게 된다. 그래서 메모리 공간에는 main 함수의 변수 a만 남게 된다. 그리고나서 코드의 흐름은 다시 main 함수로 돌아와 exampleFunc2 함수를 호출한다. exampleFunc2 함수 역시 지역변수 b c를 선언해 메모리 공간에 변수 b와 c가 각각 할당되고 20,30으로 초기화된다.

그리고 exampleFunc2 의 코드를 차례로 실행하고 함수가 종료되면, 또 함수 내에서 선언했던 변수 b와 c는 소멸하게 되고 코드의 흐름이 다시 main 함수로 돌아와 a만 메모리에 남게 된다. 그리고 main 함수도 종료되면 메모리 공간의 모든 변수가 소멸되는 것이다.

지역변수를 이해했다면 전역변수는 수월할 것이다.

아래의 예시 코드를 보자.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package main
 
import "fmt"
 
var a int = 1 //전역변수 선언
 
func localVar() int { //지역변수로 연산
    var a int = 10 //지역변수 선언
 
    a += 3
 
    return a
}
 
func globalVar() int { //전역변수로 연산
    a += 3
        
    return a
}
 
func main() {
    fmt.Println("지역변수 a의 연산: ", localVar())
    fmt.Println("전역변수 a의 연산: ", globalVar())
}
cs

코드가 실행되고 main 함수가 호출되기 전에 전역변수로 선언한 a가 메모리 공간에 할당된다. 이 변수는 프로그램이 종료될 때까지 메모리 공간에 남아있을 것이고, 어느 지역에서든 사용할 수 있다. 그리고 main 함수가 호출되고 localVar 함수도 호출된다. localVar 함수에서 지역변수 a가 선언되고 10으로 초기화된다. 아까 말한 것처럼 전역변수와 이름이 같아도 지역변수는 해당 지역에서 유효하다고 했기 때문에 오류가 나는 것이 아니라 전역변수를 가리게된다. 따라서 지역변수 a로 연산을 수행하고 종료한다. 그리고 이어서 globalVar함수를 호출하게 되는데 이 함수에서는 변수를 선언하지 않았다. 전역변수는 어느 지역에서든 사용이 가능하기 때문에 특별한 선언 없이 바로 전역변수를 사용해 연산을 하고 그 값을 반환한다. 이렇게 지역변수를 활용한 함수와 전역변수를 활용한 함수의 쓰임과 원리를 확인했다.

 

이렇게 보면 전역변수는 선언해놓고 필요할 떄마다 어디서든 쓰면 되니까 지역변수보다 훨씬 유용하게 쓰일 것처럼 보일 수 있다. 하지만 전역변수의 선언은 가급적 피해야한다. 왜냐하면 전역변수는 프로그램의 구조를 복잡하게 만들고 사용빈도와 상관 없이 프로그램이 끝날 때 까지 메모리를 차지하고있기 때문이다. 따라서 전역변수를 사용하는 것은 신중해야한다.

728x90
반응형