변수와 상수

스위프트는 데이터가 저장되는 메모리 내 주소 공간을 개발자가 쉽게 인식하고 사용할 수 있도록 변수와 상수를 제공

예를 들어 설명

  • 연도가 의미하는 1999라는 숫자 데이터가 메모리 주소 0x12345678 ~ 0x1234567B 까지에 걸쳐 저장되어 있다고 가정
  • 숫자 데이터를 꺼내어 사용할 때마다 항상 이 주소값을 사용할 수는 없다
    • 주소값이 너무 길다, 16진수 숫자들로 되어 있어 외우기 어렵다
    • 그래서 이 주소값을 “year”라는 이름으로 연결한다
"year"라는 단어를 특정 형식에 따라 사용하면 컴파일러는 내부에 저장된 메모리 주소록을 뒤진다
"year"라는 이름으로 연결된 0x12345678 ~ 0x1234567B까지의 주소를 확인하고
각각의 주소에 저장된 값을 읽어와 하나로 합친 1999라는 데이터를 만들어 준다
이름으로 메모리 주소를 등록해 두지 않았다면 저장된 값을 꺼내기 위해서
주소 공간 하나 하나를 직접 찾아 값을 합쳐서 사용해야 한다
하지만, 이름을 저장해 놓는다면 "year"라는 인식하기 쉬운 단어만으로 저장된 값을 쉽게 불러올 수 있다

이렇게 값을 저장한, 혹은 저장할 메모리 주소값을 이름으로 연결해 놓은 것을 변수와 상수라고 한다

  • 변수와 상수를 이용하여 메모리 주소에 해당하는 공간에 손쉽게 값을 저장하거나 꺼낼 수 있다
  • 일반적으로는 이 같은 과정을 떠올리는 대신 “변수와 상수에 값을 저장한다”라고 생각해도 된다
  • 변수와 상수는 값을 저장할 수 있다는 공통점이 있다
    • 상수는 한 번 저장된 값을 다른 값으로 변경할 수 없다
    • 변수는 필요에 따라 저장된 값을 몇 번이라도 다른 값으로 변경할 수 있다
  • ** 변수에는 프로그램의 실행에 따라 변하는 값을 저장하고, 상수에는 변하지 않을 값을 저장한다**
  • 변수라고 해서 아무 값이나 마음대로 저장할 수 있는 것은 아니다
  • 변수의 값을 변경할 때에는 처음 저장했던 값과 일치하는 타입이어야 한다
    • 예를 들어 설명
      변수에 처음 저장된 값이 정수였다면 이후로도 정수만 저장할 수 있다
      처음 저장한 값이 문자열이였다면 이후로 변경할 수 있는 값 역시 문자열뿐이다
    
    • 즉, 변수는 처음 입력한 값과 동일한 타입에 한해서만 값을 변경할 수 있다

굳이 상수가 있어야 하는 이유

  • 성능이나 기타 다른 기술적 이점은 차치하고라도, 프로그래밍 소스 관리 목적상 변하지 않는 값은 상수에 저장하는 것이 훨씬 효율적이다
  • 실수로 값이 변경되는 일을 막을 수 있다
  • 값의 성격이 명확이 분류된다
    • 관리하기에 용이

변수와 상수의 사용 기준이 모호할때

  • 일단 변수로 작성
  • 스위프트 2.0에서는 변수에 한번 할당된 이후로 소스 코드에서 변경되지 않은 값이 있을 경우 이를 상수로 바꾸도록 컴파일러가 조언을 해준다
  • 이 조언에 따라 적절히 상수와 변수를 조절하다 보면 변수와 상수의 선택 기준에 대해 이해하게 될 것이다

억지로 다른 자료형의 값을 넣으면??

  • 오류발생
  • 스위프트에서는 변수의 초기값이 지정되면 그 값에 의해 변수의 타입이 결정되고, 이후로는 타입 변경이 불가능하다
    • 따라서 억지로 다른 타입의 값을 집어넣으려고 한다면 컴파일 오류 로 이어지게 된다

변수와 상수를 정의하는 방법

  • 스위프트에서 변수와 상수는 반드시 먼저 선언한 다음에 사용해야 한다
    • ‘이러이러한 변수를 사용하겠다’ 또는 ‘이런 이름의 상수를 사용하겠다’라는 것을 컴파일러에 알려주기 위함
  • 변수와 상수를 선언하려면 키워드를 사용해야 한다
    • 변수는 var 키워드 사용
    • 상수는 let 키워드 사용
      변수 선언시 : var + 변수명
      상수 선언시 : let + 변수명
    

변수와 상수를 정의하는 실제 구문

  • 변수 정의
var year = 1999 // 정수형 변수
var message = "Hello, SuA" // 문자열 변수
  • 두 개의 변수 year와 message는 각각 정수 또는 문자열을 담을 목적으로 정의
    • ’=’연산자(대입 연산자) 를 통해 대입된 값을 보면 알 수 있다
      • year라는 이름을 가진 변수는 1999라는 정수를 대입
        • 정수형 타입의 변수
      • message라는 이름을 가진 변수는 “Hello SuA”라는 문자열을 대입
        • 문자열 타입의 변수
  • 한번 정해진 타입은 바꿀수 없다
    • 정수형 타입의 변수에는 이후로도 정수만 대입 가능
    • 문자열 타입의 변수에는 이후로도 문자열만 대입 가능
  • 스위프트에서 변수의 타입은 대부분 맨 처음 대입된 값에 따라 정해진다
    • 이후로는 타입 변경 불가
  • var 키워드로 선언된 변수에 처음으로 값을 대입하는 과정
    • 그 과정을 초기화(Initialize) 라고 한다
      • 대입 연산자 ‘=’를 이용하여 이루어진다

스위프트는 대부분 초기화 과정에서 변수의 타입이 결정되는데, 이때 활약하는 것이 바로 컴파일러다

  • 컴파일러 는 변수에 대압 될 값을 검토하여 가장 적절한 타입을 추론하고 그에 맞는 메모리 공간을 확보한 다음, 그곳에 값을 저장, 그때부터 해당 변수를 사용할 수 있게 된다
  • 타입에 따라 필요한 메모리 공간이 다르기 때문에, 변수의 타입을 결정하는 과정은 프로그래밍 언어의 성능과 효율성을 결정하는 중요한 요소가 되기도 한다
    • 4 바이트만 있으면 충분함에도 확장성을 너무 고려한 나머지 8 바이트나 그 이상의 공간을 잡아 놓는다면 그건 결국 메모리 낭비로 이어진다
  • 때문에 스위프트는 타입 추론기 라는 기능 모듈을 컴파일러에 별도로 내장하여, 항상 최적의 타입을 결정하고자 한다
  • 전통적인 C나 JAVA 프로그래머처럼 직접 변수의 타입을 지정하게 하기 위해 타입 어노테이션(Type Annotation) 이라는 기능을 제공하기도 한다

스위프트가 아닌 다른 일부 프로그래밍 언어에서는 변수를 선언하는 과정과 초기화 과정을 반드시 분리하여 작성하도록 강제하기도 한다

  • 먼저 선언하고 그 다음에 초기화하는 것이다
    • 예시
      var year // 1. 변수 선언
      year = 1999 // 2. 변수 초기화
    
  • 스위프트에서는 이 두 과정을 나눌 필요없이 한꺼번에 처리할 수 있다
    • 예시
      let birthYear = 1991 // 정수형 상수 
      let welecomeMessage = "어서오세요" // 문자열 상수
    
    • 변수에서도 큰 차이는 없다
    • 선언 키워드가 let이 아니라 var라는 점만 다를 뿐이다

스위프트에서 선언과 초기화의 분리

  • 스위프트에서 선언과 초기화의 분리가 가능하다
  • 다만 변수와 상수를 구분할 필요가 있다
  • 변수의 경우 일단 선언만 하고, 이후 실제로 필요한 시점에 초기화해도 된다
  • 스위프트에서 상수는 선언과 초기화가 동시에 이루어져야 한다
    • 예외적으로 상수에서 선언과 초기화를 분리할 수 있는 경우도 있다

스위프트에서 선언과 초기화를 분리하여 정의하는 방법

  • 변수의 선언과 초기화를 분리한 구문
    • 예시
      var year: Int // 변수 선언
      year = 1991 // 선언된 변수의 초기화
    
    • 작성된 위의 구문에서 새로운 부분이 있다
      • ’: Int’
        • 이는 변수의 타입을 직접 정의해주는, 타입 어노테이션(Type Annotation)이라는 문법이다