상수

상수는 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

spring boot Graphql 요청 Environment 접근

spring boot Graphql 요청 Environment 접근

이번에는 Spring Boot GraphQL 환경변수(쿼리명, 파라미터명, 값, 받고자하는 데이터명 등)들을 Controller에서 접근하는 방법을 포스팅하려고 한다. 보통 Rest한 서버의 Controller에서는 @PathVariable , @RequestBody 등과 같은 어노테이션을 이용해서 파라미터들에 접근할 수 있는데 요청자체가 body안에 json형태로 들어오는 graphQL은 위와...

Read More
인터페이스

인터페이스

  • Java
  • 2021년 12월 8일

1. 인터페이스란? 자바의 다형성을 극대화하여 개발코드 수정을 줄이고 유지보수를 용이하게 하기 위함 다형성? 동일한 메시지를 수신했을 때 객체의 타입에 따라 다르게 응답할 수 있는 능력 1) 추상클래스와 인터페이스 차이 추상메서드를 가짐으로써 다형성을 극대화하면서 어떤 역할을 구현하는 방법(객체들이 따라야 하는 책임의 집합을 서술한 것)이라는 공통...

Read More
Clean Code

Clean Code

  • Books
  • 2021년 1월 22일

1장. 깨끗한 코드 코드 품질을 측정하는 유일한 척도 = 분당 내지르는 ‘WTF!’ 횟수 코드는 요구사항을 상세히 표현하는 수단 ( 기계가 실행할 정도로 상세하게 요구사항을 명시하는 작업 = 프로그래밍 ) 작성자가 아닌 사람도 읽고 고치기 쉽고 단순하고 직접적이다 중복을 피하고 한 기능만 수행하게 작제 추상화하기 프로그래밍은 코드를 읽는 시간 대 짜는 시간 비율이 9:1 잘...

Read More