상수

상수는 Immutable(불변)한 특징을 갖으며 한 번 할당된 값을 변경할 수 없는 변수이다.

const a int = 1
const b string = "hi"
const d = 10  //자료형을 생략가능하다.
f := 10 //이는 자동으로 var 형태의 변수로 선언이 되기 때문에 상수가 될 수 없다.

var runTimeVar int = 1
const e = runTimeVar * 10  //runTimeVar는 런타임에 값이 할당되기 때문에 컴파일타임에 d의 값을 할당할 수 없어 error가 발생한다.

상수 키워드는 const로 선언방식은 변수 var와 같고 short assginment statement는 var키워드 전용이기 때문에 상수는 짧은 대입문 사용이 불가능 하다. 또한, 반드시 컴파일 타임에 실행이 가능한 표현식이어야만 한다.


const a,b,c  = 1, true, "hi"
const d = [5]int{1,2,3,4,5}  //error

상수에는 문자열, 숫자, bool타입만 가능하고, js같이 자료구조(배열,map 등)와 같이 내부적으로 포인터를 이용하는 타입들은 상수로 표현이 불가능하다. go에서 상수는 컴파일타임에 실행이 가능해야하기 때문에 내부의 값이 변할 수 있는 타입들은 상수로 표현이 불가능하다.


const a1 int = 1
const b1 float64 = 3

const sum1 = a1 + b1
fmt.Printf("%d, %T\n", sum, sum)  //error

const a2 = 1
const b2 = 3

const sum = a2 + b2
fmt.Printf("%d, %T\n", sum, sum)  //4, int

const casting = 1 / 3.0 //암묵적으로 형변환이 일어난다.
fmt.Printf("%g, %T\n", sum, sum)  // 0.333333.., float64

타입을 생략해서 표현할 수 도 있는데 이렇게 되면 실제로 사용되는 시점(명시적 형변환)전까지는 type이 존재하지 않는다.

그리고, 상수의 산술연산에서 암묵적 형변환을 지원해서 조금 더 유연하게 표현할 수 있다.



1. 상수 사용시기

상수는 변수에 비해 매우 큰 표현 범위를 갖을 수 있어 높은 정밀도를 제공하기 때문에 보다 정확한 계산을 위해 사용되거나 열거형(Enum) 을 만드는데 사용할 수 있다.

fmt (
  "fmt"
  "math"
)

func main(){
  const maxInt = math.MaxInt64  //int64의 최대값
  const maxConst = 1 << 100   //int 표현의 범위를 벗어났지만 실제 int로 명시하기 전에는 int타입이 아니기 때문에 표현이 가능하다.

  fmt.Println(maxInt)   //9223372036854775807
  fmt.Println(maxConst)  //함수로 표현하려고 하면 타입의 명시가 일어나 int범위를 벗어나 overflow가 발생한다.
  ftm.Println(maxConst * 0.1) //1.2676506002282295e+29  <-- 산술연산 중에 암묵적으로 float로 형변환이 일어나 overflow가 발생하지 않는다.
}

const i1 = 14345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345   //error

정수형 상수도 저장할 수 있는 한계가 존재하기는 한다.



2. Enum

Go는 Java나 C++ 처럼 enum을 제공하지 않기 때문에 C에서 enum을 비슷하게 만들어 사용하는 것처럼 go도 const를 이용해서 enum을 만들어 사용할 수 있다. 또한, iota라는 상수 생성자를 제공해서 순차적으로 증가하는 상수값을 쉽게 선언 할 수 있다.

const (
  a = 1   //1으로 시작
  b       //1
  c       //1
)
const (
  a = iota  //0으로 시작
  b         //1
  c         //2
)
const (
  a = iota + 1   //1으로 시작
  b              //2
  c              //3
)
const (
  a = 1 << iota   //1
  b               //2
  c               //4
  d               //8
)



3. 상수와 리터럴

리터럴은 변수의 값이 변하지 않는 데이터로 메모리 안의 존재하는 값 그자체를 의미한다.

var a int = 1

변수를 할당하는 데 있어 주로 우측에 오는 값으로 1이라는 값 그 자체는 변경할 수 없는데 이를 리터럴이라고 한다. 1이라는 값이 2가 될 수 없는 것이다.

var s string = "ex"

string의 “ex” 도 리터럴인데 ex라는 값이 heap에 한번 할당되고 값이 변경되지 않기 때문이다. 우리가 string변수를 연산자를 이용해서 문자열을 붙이는 것은 기존의 ex라는 값에 붙이는 것이 아니라 heap공간에 ex+새로운 문자열 을 새로 할당하는 방식으로 동작하기 때문에 string의 우측에 오는 값도 리터럴이다.


Note

리터럴도 변하지 않는 값이기 때문에 상수와 햇갈릴 수 있지만, 상수는 값을 한번만 저장하고 변경이 불가능한 메모리 공간이고, 리터럴은 값 그자체로 변경이 불가능한 값이다.




Reference

https://tramamte.github.io/2018/07/03/deep-inside-constants/

『Tucker의 Go 언어 프로그래밍』 스터디 요약 노트

Tags :

Related Posts

Go in Action

Go in Action

  • Books
  • 2022년 3월 29일

저는 개인적으로 GoLang을 접한지는 꽤 되었습니다. 제가 Go를 학습할때는 인터넷을 통해 충분히 학습할 수 있었는 데, 키워드들이 많지 않았고 http://golang.site 에 대부분 필요한 내용은 설명되어있어 무리없이 학습할 수 있었습니다. 그런데 책을 구매하게 된 이유는 요즘 읽을 책이 마땅치 않았기도 하고, Go 책을 개인적으로 소장하고 싶어 구매해본 책입니다. 책이 나온지는 꽤 된 책입니다. 하지만, go언어가 version이 높아지면서 언어에 큰 변화가 생기지 않았기 때문에 별 무리 없이 책을 읽을 수 있었습니다....

Read More
페이징 기능 추가하기

페이징 기능 추가하기

각종 css와 shortcode들을 추가했던 이전 글 에 이어 이번에는 pagination을 추가해보려고 한다. 저는 각 카테고리의 메인 페이지에서는 해당 카테고리의 글들을 paging처리하여 모두 볼 수 있게 구성을 하고 싶었는 데, 제가 사용하고 있는 docport 테마는 paging처리가 들어있지 않은 테마였다. 그래서 hugo 공식사이트 를 참고하여 적용시킨 방법을 공유하려고 한다....

Read More
List를 Array로 Array를 List로 변환

List를 Array로 Array를 List로 변환

  • Java
  • 2021년 5월 27일

List와 Array간의 변환은 기본적으로 for문을 이용하여 하나하나 바꾸어주면 변환이 가능하다. 하지만 for이 아닌 stream API를 이용해서 더 간편하게 바꿀 수 있는 방법을 정리한다. 1. List에서 Array로 변환 1) List -&gt; Object[] List에서 Wrapper객체배열로 바꾸는 것은 List의 toArray() 함수를 이용하면 쉽게 바꿀 수 있고 toArray() 의 매개변수로 변환할 객체배열을 넘겨주면 해당 타입의 배열로 바꾸어 반환된다....

Read More