Go에서 変数와 상수를 사용하는 방법

변수는 프로그래밍의 중요한 개념으로 마스터하는 것이 중요합니다. 변수는 프로그램에서 사용하는 값을 대신하는 기호입니다.

이 튜토리얼에서는 변수의 기본 사항과 Go 프로그램에서 변수를 사용하기 위한 모범 사례를 다룰 것입니다.

변수 이해하기

기술적인 용어로, 변수는 기호 이름이나 식별자에 연결된 값에 저장 위치를 할당하는 것입니다. 우리는 변수 이름을 사용하여 컴퓨터 프로그램 내에서 해당 저장된 값을 참조합니다.

변수를 값에 묶인 이름이 있는 라벨로 생각할 수 있습니다.

예를 들어 정수 1032049348이 있고 이를 반복해서 긴 숫자를 다시 입력하는 대신 변수에 저장하려고 합니다. 이를 위해 기억하기 쉬운 이름을 사용할 수 있습니다. 예를 들어 변수 i를 사용합니다. 변수에 값을 저장하기 위해 다음과 같은 구문을 사용합니다:

i := 1032049348

이 변수를 값에 묶인 라벨로 생각할 수 있습니다.

라벨에는 변수 이름 i가 적혀 있고, 정수 값 1032049348에 묶여 있습니다.

구문 i := 1032049348은 몇 가지 부분으로 구성된 선언 및 할당 문장입니다:

  • 변수 이름 (i)
  • 단축 변수 선언 할당 (:=)
  • 변수 이름(1032049348)에 할당되는 값
  • Go에 의해 추론된 데이터 타입(int)

다음 섹션에서 타입을 명시적으로 설정하는 방법을 살펴보겠습니다.

이 모든 부분이 함께 변수 i를 정수 1032049348의 값과 동일하게 설정하는 문장을 구성합니다.

변수에 값을 할당하는 즉시 해당 변수를 초기화하거나 생성합니다. 이 작업을 마치면 값 대신 변수를 사용할 준비가 된 것입니다.

i1032049348의 값과 동일하게 설정한 후에는 정수 대신 i를 사용할 수 있으므로 출력해 봅시다:

package main

import "fmt"

func main() {
	i := 1032049348
	fmt.Println(i)
}
Output
1032049348

변수를 사용하여 빠르고 쉽게 수학 연산을 할 수도 있습니다. i := 1032049348을 사용하여 다음 구문으로 정수 값 813을 뺄 수 있습니다:

fmt.Println(i - 813)
Output
1032048535

이 예제에서 Go는 수학 연산을 수행하여 변수 i에서 813을 빼서 합계 1032048535를 반환합니다.

수학에 관해 언급하자면, 변수는 수학 방정식의 결과와 동일하게 설정될 수 있습니다. 두 숫자를 더하고 그 합계의 값을 변수 x에 저장할 수도 있습니다:

x := 76 + 145

이 예제가 대수학과 유사하게 보일 수 있다는 점에 주목하십시오. 공식과 방정식 내에서 숫자와 양을 나타내기 위해 문자와 기호를 사용하는 것처럼 변수는 데이터 타입의 값을 나타내는 상징적인 이름입니다. Go 구문을 올바르게 하려면 변수가 방정식의 왼쪽에 있는지 확인해야 합니다.

이제 x를 출력해 봅시다:

package main

import "fmt"

func main() {
	x := 76 + 145
	fmt.Println(x)
}
Output
221

Go가 221 값을 반환한 이유는 변수 x76145의 합계와 같게 설정되었기 때문입니다.

변수는 정수뿐만 아니라 모든 데이터 유형을 나타낼 수 있습니다:

s := "Hello, World!"
f := 45.06
b := 5 > 9 // 부울 값은 true 또는 false를 반환합니다
array := [4]string{"item_1", "item_2", "item_3", "item_4"}
slice := []string{"one", "two", "three"}
m := map[string]string{"letter": "g", "number": "seven", "symbol": "&"}

이러한 변수 중 하나를 인쇄하면 Go는 해당 변수와 동일한 것을 반환합니다. 문자열 slice 데이터 유형에 대한 할당 문을 사용해 보겠습니다:

package main

import "fmt"

func main() {
	slice := []string{"one", "two", "three"}
	fmt.Println(slice)
}
Output
[one two three]

우리는 []string{"one", "two", "three"}의 슬라이스 값을 변수 slice에 할당한 다음 fmt.Println 함수를 사용하여 slice를 호출하여 해당 값을 출력했습니다.

변수는 컴퓨터 내에서 지정된 값을 허용하는 작은 메모리 영역을 확보하여 해당 공간과 연결되는 방식으로 작동합니다.

변수 선언

Go에서는 여러 가지 방법으로 변수를 선언할 수 있으며, 경우에 따라 정확히 동일한 변수와 값을 선언할 수 있는 방법이 두 가지 이상 있습니다.

우리는 초기화 없이 int 데이터 유형의 i라는 변수를 선언할 수 있습니다. 즉, 값을 넣을 공간을 선언하지만 초기 값은 지정하지 않습니다:

var i int

이렇게 하면 int 데이터 유형의 i로 선언된 변수가 생성됩니다.

우리는 다음과 같은 예제에서처럼 등호(=) 연산자를 사용하여 값을 초기화할 수 있습니다:

var i int = 1

Go에서 이러한 두 가지 선언 형식을 긴 변수 선언이라고 합니다.

또한 짧은 변수 선언을 사용할 수도 있습니다:

i := 1

이 경우, i라는 변수와 int 데이터 타입이 있습니다. 데이터 타입을 지정하지 않으면 Go가 데이터 타입을 추론합니다.

변수를 선언하는 세 가지 방법으로, Go 커뮤니티는 다음과 같은 관용구를 채택했습니다:

  • 변수를 초기화하지 않을 때만 긴 형식, var i int를 사용하세요.

  • 선언과 동시에 초기화할 때는 짧은 형식, i := 1을 사용하세요.

  • Go가 데이터 타입을 추론하지 않길 원하지만 짧은 변수 선언을 사용하려면, 다음 구문과 같이 원하는 타입으로 값을 감싸면 됩니다:

i := int64(1)

값을 초기화할 때 긴 변수 선언 형식을 사용하는 것은 Go에서 관용적이지 않습니다:

var i int = 1

다른 사람들이 프로그램을 원활하게 읽을 수 있도록 Go 커뮤니티가 일반적으로 변수를 선언하는 방식을 따르는 것이 좋습니다.

제로 값

모든 내장 타입은 제로 값을 가지고 있습니다. 할당된 모든 변수는 값이 할당되지 않았더라도 사용할 수 있습니다. 다음 타입들의 제로 값을 확인할 수 있습니다:

package main

import "fmt"

func main() {
	var a int
	var b string
	var c float64
	var d bool

	fmt.Printf("var a %T = %+v\n", a, a)
	fmt.Printf("var b %T = %q\n", b, b)
	fmt.Printf("var c %T = %+v\n", c, c)
	fmt.Printf("var d %T = %+v\n\n", d, d)
}
Output
var a int = 0 var b string = "" var c float64 = 0 var d bool = false

우리는 fmt.Printf 구문에서 %T 동사를 사용했습니다. 이는 함수에게 변수의 데이터 타입을 출력하도록 지시합니다.

Go에서는 모든 값이 제로 값을 가지고 있기 때문에 다른 언어들처럼 정의되지 않은 값을 가질 수 없습니다. 예를 들어, 어떤 언어에서는 불리언정의되지 않음, , 또는 거짓일 수 있어 변수에 세 가지 상태를 허용합니다. Go에서는 불리언 값에 대해 두 가지 이상의 상태를 가질 수 없습니다.

변수 명명: 규칙 및 스타일

변수의 명명은 상당히 유연하지만, 염두에 두어야 할 몇 가지 규칙이 있습니다:

  • 변수 이름은 단 하나의 단어로만 구성되어야 합니다(즉, 공백이 없어야 함).
  • 변수 이름은 문자, 숫자, 밑줄(_)로만 구성되어야 합니다.
  • 변수 이름은 숫자로 시작할 수 없습니다.

이러한 규칙을 따라, 유효한 변수명과 유효하지 않은 변수명을 모두 살펴보겠습니다:

Valid Invalid Why Invalid
userName user-name Hyphens are not permitted
name4 4name Cannot begin with a number
user $user Cannot use symbols
userName user name Cannot be more than one word

또한, 변수명을 지을 때 대소문자를 구분한다는 점을 염두에 두십시오. 이러한 이름들 userName, USERNAME, UserName, uSERnAME는 모두 완전히 다른 변수입니다. 프로그램 내에서 유사한 변수명을 사용하지 않는 것이 가장 좋은 방법입니다. 이를 통해 현재와 미래의 협력자들과 함께 변수를 명확하게 유지할 수 있습니다.

변수는 대소문자를 구분하지만, Go에서 변수의 첫 글자의 대소문자는 특별한 의미를 가집니다. 변수가 대문자로 시작하면, 해당 변수는 선언된 패키지 외부에서 접근 가능합니다(또는 exported). 변수가 소문자로 시작하면, 선언된 패키지 내에서만 사용할 수 있습니다.

var Email string
var password string

Email은 대문자로 시작하므로 다른 패키지에서 접근할 수 있습니다. password는 소문자로 시작하므로, 선언된 패키지 내에서만 접근 가능합니다.

Go에서는 매우 간결한(또는 짧은) 변수명을 사용하는 것이 일반적입니다. userNameuser 중 하나를 변수로 사용할 경우, user를 선택하는 것이 관용적입니다.

또한 변수명의 간결함은 범위와도 관련이 있습니다. 변수가 존재하는 범위가 작을수록 변수명도 작아야 합니다.

names := []string{"Mary", "John", "Bob", "Anna"}
for i, n := range names {
	fmt.Printf("index: %d = %q\n", i, n)
}

우리는 변수 names를 더 큰 범위에서 사용하므로, 프로그램에서 그것이 무엇을 의미하는지 기억하는 데 도움이 되는 더 의미 있는 이름을 지어주는 것이 일반적입니다. 그러나 in 변수는 바로 다음 줄에서 사용된 후 다시 사용되지 않습니다… 이러한 이유로, 코드를 읽는 사람이 변수가 어디에 사용되는지 또는 그 의미가 무엇인지 혼란스러워하지 않을 것입니다.

다음으로, 변수 스타일에 대한 몇 가지 주의사항을 살펴보겠습니다. 스타일은 여러 단어로 된 이름에 대해 밑줄 대신 MixedCaps 또는 mixedCaps를 사용하는 것입니다.

Conventional Style Unconventional Style Why Unconventional
userName user_name Underscores are not conventional
i index prefer i over index as it is shorter
serveHTTP serveHttp acronyms should be capitalized

스타일에 관한 가장 중요한 점은 일관성을 유지하고, 팀이 그 스타일에 동의하는 것입니다.

변수 재할당

‘변수’라는 단어가 암시하듯이, 우리는 Go 변수를 쉽게 변경할 수 있습니다. 이는 이전에 할당된 변수에 다른 값을 연결할 수 있음을 의미합니다. 재할당이 가능하다는 것은 프로그램 과정에서 이미 초기화된 변수에 사용자가 생성한 값을 받아들여야 할 수도 있고, 이전에 정의된 것에 대한 할당을 변경해야 할 수도 있기 때문에 유용합니다.

이미 정의된 변수가 무엇인지 명확하지 않은 다른 사람이 작성한 대규모 프로그램을 작업할 때, 변수를 쉽게 재할당할 수 있다는 것을 아는 것이 유용할 수 있습니다.

int 타입의 i라는 변수에 76 값을 할당한 다음, 42라는 새로운 값을 할당해 봅시다:

package main

import "fmt"

func main() {
	i := 76
	fmt.Println(i)

	i = 42
	fmt.Println(i)
}
Output
76 42

이 예제는 먼저 변수 i에 정수 값을 할당한 다음, 이번에는 42 값을 할당하여 변수 i를 재할당할 수 있음을 보여줍니다.

참고: 변수를 선언하고 초기화할 때는 :=를 사용할 수 있지만, 이미 선언된 변수의 값을 단순히 변경하려면 등호 연산자(=)만 사용하면 됩니다.

Go는 타입이 지정된 언어이므로 한 타입을 다른 타입에 할당할 수 없습니다. 예를 들어, int 타입의 변수에 "Sammy" 값을 할당할 수 없습니다:

i := 72
i = "Sammy"

서로 다른 타입을 서로 할당하려고 하면 컴파일 시간 오류가 발생합니다:

Output
cannot use "Sammy" (type string) as type int in assignment

Go에서는 변수 이름을 두 번 이상 사용할 수 없습니다:

var s string
var s string
Output
s redeclared in this block

동일한 변수 이름에 대해 짧은 변수 선언을 두 번 이상 사용하려고 하면 컴파일 오류가 발생할 수도 있습니다. 이는 실수로 인해 발생할 수 있으므로 오류 메시지가 무엇을 의미하는지 이해하는 것이 도움이 됩니다:

i := 5
i := 10
Output
no new variables on left side of :=

변수 선언과 마찬가지로 변수 이름을 신중하게 지정하면 나중에 다시 살펴볼 때 프로그램의 가독성을 높여줄 수 있습니다.

다중 할당

Go는 또한 한 줄에 여러 값을 여러 변수에 할당할 수 있게 해줍니다. 이러한 각 값은 서로 다른 데이터 타입일 수 있습니다:

j, k, l := "shark", 2.05, 15
fmt.Println(j)
fmt.Println(k)
fmt.Println(l)
Output
shark 2.05 15

이 예제에서 변수 j는 문자열 "shark"에 할당되었고, 변수 k는 부동 소수점 2.05에 할당되었으며, 변수 l는 정수 15에 할당되었습니다.

이러한 방식으로 한 줄에 여러 변수에 여러 값을 할당하면 코드의 줄 수를 줄일 수 있습니다. 하지만 코드의 가독성을 해치지 않는 것이 중요합니다.

전역 및 지역 변수

프로그램 내에서 변수를 사용할 때는 변수 범위를 염두에 두어야 합니다. 변수의 범위는 특정 프로그램의 코드 내에서 해당 변수에 접근할 수 있는 특정 위치를 나타냅니다. 즉, 모든 변수가 특정 프로그램의 모든 부분에서 접근 가능한 것은 아닙니다. 일부 변수는 전역 변수가 되고 일부는 지역 변수가 될 것입니다.

전역 변수는 함수 외부에 존재합니다. 지역 변수는 함수 내부에 존재합니다.

전역 및 지역 변수의 동작을 살펴보겠습니다:

package main

import "fmt"


var g = "global"

func printLocal() {
	l := "local"
	fmt.Println(l)
}

func main() {
	printLocal()
	fmt.Println(g)
}
Output
local global

여기서 우리는 var g = "global"을 사용하여 함수 외부에 전역 변수를 생성합니다. 그런 다음 printLocal() 함수를 정의합니다. 함수 내부에서 l이라는 지역 변수가 할당되고 출력됩니다. 프로그램은 printLocal()을 호출한 후 전역 변수 g를 출력하며 끝납니다.

g가 전역 변수이기 때문에 printLocal()에서 참조할 수 있습니다. 이전 프로그램을 수정하여 그렇게 해보겠습니다:

package main

import "fmt"


var g = "global"

func printLocal() {
	l := "local"
	fmt.Println(l)
	fmt.Println(g)
}

func main() {
	printLocal()
	fmt.Println(g)
}
Output
local global global

먼저 전역 변수 g를 선언하고, var g = "global"입니다. main 함수에서 printLocal 함수를 호출하면, 지역 변수 l을 선언하고 출력합니다, fmt.Println(l). 그런 다음 printLocal은 전역 변수 g를 출력합니다, fmt.Println(g). gprintLocal 내에서 정의되지 않았지만, 전역 범위에서 선언되었기 때문에 여전히 접근할 수 있습니다. 마지막으로 main 함수도 g를 출력합니다.

이제 함수 외부에서 지역 변수를 호출해 보겠습니다:

package main

import "fmt"

var g = "global"

func printLocal() {
	l := "local"
	fmt.Println(l)
}

func main() {
	fmt.Println(l)
}

Output
undefined: l

지역 변수는 할당된 함수 외부에서 사용할 수 없습니다. 그렇게 하려고 하면 컴파일 시 undefined 오류가 발생합니다.

전역 변수와 지역 변수에 동일한 변수 이름을 사용하는 또 다른 예제를 살펴보겠습니다:

package main

import "fmt"

var num1 = 5

func printNumbers() {
	num1 := 10
	num2 := 7  

	fmt.Println(num1)
	fmt.Println(num2)
}

func main() {
	printNumbers()
	fmt.Println(num1)
}
Output
10 7 5

이 프로그램에서 우리는 num1 변수를 두 번 선언했습니다. 처음에는 전역 범위에서 num1을 선언했고, var num1 = 5, 그리고 printNumbers 함수의 지역 범위 내에서 다시 num1 := 10으로 선언했습니다. main 프로그램에서 num1을 출력하면 값 5가 출력됩니다. 이는 main이 전역 변수 선언만 볼 수 있기 때문입니다. 하지만 printNumbers 함수에서 num1을 출력하면 지역 선언을 보게 되어 값 10이 출력됩니다. printNumbersnum1이라는 새 변수를 생성하고 값 10을 할당했지만, 이는 값 5를 가진 전역 num1 인스턴스에 영향을 주지 않습니다.

변수 작업을 할 때, 프로그램의 어느 부분이 각 변수에 접근해야 하는지도 고려해야 합니다; 그에 따라 전역 또는 지역 변수를 채택하세요. Go 프로그램에서는 지역 변수가 일반적으로 더 흔합니다.

상수

상수는 변수와 비슷하지만, 선언된 후에는 수정할 수 없습니다. 상수는 프로그램에서 여러 번 사용되지만 변경되지 않아야 하는 값을 정의할 때 유용합니다.

예를 들어, 쇼핑카트 시스템에서 세율을 선언하고 싶다면, 상수를 사용하고 프로그램의 여러 부분에서 세금을 계산할 수 있습니다. 미래의 어느 시점에서 세율이 변경되면, 프로그램에서 단 하나의 위치에서 값을 변경하면 됩니다. 변수를 사용했다면, 프로그램의 어딘가에서 실수로 값이 변경될 수 있으며, 이는 잘못된 계산으로 이어질 수 있습니다.

상수를 선언하려면, 다음과 같은 문법을 사용할 수 있습니다:

const shark = "Sammy"
fmt.Println(shark)
Output
Sammy

선언된 후에 상수를 수정하려고 시도하면, 컴파일 시간 에러를 받게 됩니다:

Output
cannot assign to shark

상수는 untyped일 수 있습니다. 이는 정수형 데이터와 같은 숫자를 다룰 때 유용할 수 있습니다. 상수가 untyped라면, 명시적으로 변환되지만, typed 상수는 그렇지 않습니다. 상수를 어떻게 사용할 수 있는지 살펴보겠습니다:

package main

import "fmt"

const (
	year     = 365
	leapYear = int32(366)
)

func main() {
	hours := 24
	minutes := int32(60)
	fmt.Println(hours * year)    
	fmt.Println(minutes * year)   
	fmt.Println(minutes * leapYear)
}
Output
8760 21900 21960

종류를 선언할 때 상수에 타입을 지정하면, 정확히 그 타입이 됩니다. 여기서 leapYear라는 상수를 선언할 때, 데이터 타입 int32으로 정의합니다. 따라서 이는 typed 상수로, 오로지 int32 데이터 타입으로만 작동할 수 있습니다. year라는 상수는 타입을 주지 않으므로, untyped로 간주됩니다. 이렇게 하면, 모든 정수 데이터 타입으로 사용할 수 있습니다.

hours가 정의될 때, 타입을 명시적으로 주지 않았기 때문에 int 타입으로 추론되었습니다, hours := 24. minutes를 선언할 때는 명시적으로 int32로 선언했습니다, minutes := int32(60).

이제 각 계산을 하나씩 거쳐보고, 왜 그런지 이해해봅시다:

hours * year

이 경우, hoursint 타입이고, years타입이 지정되지 않음입니다. 프로그램이 컴파일될 때, yearsint 타입으로 명시적으로 변환하여 곱셈 연산이 성공할 수 있게 합니다.

minutes * year

이 경우, minutesint32 타입이고, year타입이 지정되지 않음입니다. 프로그램이 컴파일될 때, yearsint32 타입으로 명시적으로 변환하여 곱셈 연산이 성공할 수 있게 합니다.

minutes * leapYear

이 경우, minutesint32 타입이고, leapYear타입이 지정된 int32 상수입니다. 이번에는 두 변수가 이미 같은 타입이므로 컴파일러가 할 일이 없습니다.

타입이 지정된 두 타입을 곱하려고 하는데 호환되지 않는다면, 프로그램은 컴파일되지 않습니다:

fmt.Println(hours * leapYear)
Output
invalid operation: hours * leapYear (mismatched types int and int32)

이 경우, hoursint 타입으로 추론되었고, leapYearint32 타입으로 명시적으로 선언되었습니다. Go는 타입이 지정된 언어이므로, intint32는 수학적 연산에 호환되지 않습니다. 이들을 곱하려면 int32 또는 int 타입으로 변환해야 합니다.

결론

이 튜토리얼에서는 Go 내에서 변수의 몇 가지 일반적인 사용 사례를 살펴보았습니다. 변수는 프로그래밍의 중요한 구성 요소로서, 프로그램에서 사용하는 데이터 타입의 값을 대표하는 기호 역할을 합니다.

Source:
https://www.digitalocean.com/community/tutorials/how-to-use-variables-and-constants-in-go