관리 메뉴

나만을 위한 블로그

[Swift] 변수와 상수, 자료형 본문

iOS/Swift

[Swift] 변수와 상수, 자료형

참깨빵위에참깨빵 2024. 1. 14. 19:48
728x90
반응형

맥북의 Xcode로 스위프트를 사용할 수 있긴 하지만 윈도우 환경에서 스위프트 문법을 공부하고자 할 경우 아래 사이트에서 간단한 스위프트 코드를 실행할 수 있다.

 

https://www.tutorialspoint.com/compile_swift_online.php

 

Online Swift Compiler | Run Swift Code Online

Online Swift Compiler to Execute and Run Swift Code Online - The best Online Swift Compiler and Editor to provide an easy to use and simple IDE (Integrated Development Environment) to Edit, Save, Compile, Run and Share Swift Code with in your browser itsel

www.tutorialspoint.com

 

또는 Replit이란 곳에서도 웹에서 스위프트 코드를 실행할 수 있다.

 

https://replit.com/new/swift

 

Sign Up

Run code live in your browser. Write and run code in 50+ languages online with Replit, a powerful IDE, compiler, & interpreter.

replit.com

 

이외에도 vs code에 플러그인을 설치하니 마니 하는데 어차피 맥북이 있는데 윈도우의 vs code를 더 무겁게 해야 할까 생각되서 그냥 웹 에디터로 만족하기로 했다.

 

코드 에디터는 준비된 것 같으니 스위프트 기초 문법부터 시작한다. 먼저 변수와 상수를 선언하는 방법을 보고 스위프트의 자료형을 확인한다.

아래는 상수, 변수에 대한 스위프트 공식문서의 내용이다.

 

https://docs.swift.org/swift-book/documentation/the-swift-programming-language/thebasics/#Constants-and-Variables

 

Documentation

 

docs.swift.org

상수, 변수는 이름을 특정 타입의 값(숫자 또는 문자열)과 연결한다. 상수의 값은 한 번 설정되면 바꿀 수 없지만 변수는 나중에 다른 값으로 설정 가능하다. 상수, 변수는 사용하기 전에 선언해야 한다. let으로 상수를 선언하고 var로 변수를 선언한다. 아래는 유저의 로그인 횟수를 추적하기 위해 상수, 변수를 사용하는 방법 예시다
let maximumNumberOfLoginAttempts = 10
var currentLoginAttempt = 0
이 코드는 maximumNumberOfLoginAttempts라는 상수를 선언하고 값을 10으로 지정한다. 그 후 currentLoginAttempt 변수를 선언하고 초기값으로 0을 지정한다. 여기선 최대값이 바뀌지 않으므로 허용되는 최대 로그인 시도 횟수가 상수로 선언된다. 현재 로그인 시도 카운터는 로그인 시도 실패 시마다 증가해야 하므로 변수로 선언된다. 코드에 저장된 값이 바뀌지 않았다면 항상 let을 써서 상수로 선언한다. 바뀌는 값을 저장하는 데만 변수를 써라

 

스위프트도 코틀린처럼 변수에 타입을 지정하지 않아도 값을 통해 추론 가능한 듯하다.

replit 기준으로 아래 예시를 실행하면 따로 타입을 지정하지 않더라도 정상 작동하는 걸 볼 수 있다.

 

let AGE = 13
let NAME = "철수"
var isMale = true
print(AGE is Int)
print(NAME == "영희")
print(isMale is Bool)

 

다른 프로그래밍 언어를 사용한 적이 있다면 상수를 선언하고 다른 값을 이 상수에 대입하려 하면 에러가 발생하는 걸 본 적이 있을 것이다. 스위프트에서는 아래와 같은 에러를 띄운다.

 

let AGE = 13
AGE = 14

 

그리고 스위프트에서의 타입 체크는 코틀린과 동일한 is 키워드로 판별하는 걸 볼 수 있다.

그럼 변수, 상수에 타입은 어떻게 지정하는가?

 

https://docs.swift.org/swift-book/documentation/the-swift-programming-language/thebasics/#Type-Annotations

 

Documentation

 

docs.swift.org

상수, 변수 선언 시 타입 어노테이션을 제공해서 상수, 변수가 저장 가능한 값의 종류를 명확히 할 수 있다. 상수, 변수명 뒤에 콜론을 쓰고 그 뒤에 공백, 사용할 타입 이름을 써서 타입 어노테이션을 작성한다. 아래는 변수가 문자열 값을 저장할 수 있단 걸 보여주기 위해 welcomeMessage 변수에 타입 어노테이션을 적용한다
var welcomeMessage: String
최종 변수명 뒤에 단일 타입 어노테이션을 써서 쉼표로 한 줄에 같은 타입의 여러 관련 변수를 정의할 수 있다
var red, green, blue: Double
실제로 타입 어노테이션을 써야 하는 경우는 거의 없다. 정의된 곳에서 상수, 변수에 대한 초기값을 제공하면 스위프트는 타입 안정성 및 타입 추론으로 거의 항상 해당 상수, 변수에 쓰일 타입을 추론할 수 있다

 

콤마로 특정 타입의 여러 변수를 설정할 경우, 아래와 같이 =을 쓰고 값을 초기화할 순 없다.

var red, green, blue: Double = 1.0
print(red, green, blue)

// main.swift:1:5: error: type annotation missing in pattern

 

대신 아래와 같이 써야 한다.

var red, green, blue: Double
red = 1.0
green = 1.1
blue = 1.2

print(red, green, blue)
// 1.0 1.1 1.2

 

그럼 상수, 변수의 네이밍에 관해선 스위프트 공식문서는 어떻게 말하고 있는가?

 

https://docs.swift.org/swift-book/documentation/the-swift-programming-language/thebasics/#Naming-Constants-and-Variables

 

Documentation

 

docs.swift.org

상수, 변수명에는 유니코드 문자를 포함한 거의 모든 문자가 포함될 수 있다. 상수, 변수명에는 공백, 수학 기호, 화살표, 개인용 유니코드 스칼라 값, 선, 상자 그리기 문자가 포함될 수 없다. 이름 안의 다른 곳에 문자가 포함될 수 있지만 숫자로 시작할 수 없다. 특정 타입의 상수, 변수를 선언한 후에는 같은 이름으로 재선언하거나 다른 타입의 값을 저장하게 변경할 수 없다. 상수 <-> 변수 간 전환도 불가능하다
예약된 스위프트 키워드와 같은 이름을 상수, 변수에 지정해야 하는 경우 이름으로 사용할 때 키워드를 백틱으로 묶는다. 선택의 여지가 전혀 없지 않다면 키워드를 이름으로 쓰지 마라. 기존 변수값을 호환 가능한 타입의 다른 값으로 바꿀 수 있다
var friendlyWelcome = "Hello!"
friendlyWelcome = "Bonjour!"
// friendlyWelcome is now "Bonjour!"

 

정리하면 스위프트의 상수, 변수명으로 쓸 수 없는 건 아래와 같다.

 

  • 공백
  • 숫자로 시작하는 이름
  • 수학 기호
  • 화살표
  • 개인용 유니코드 스칼라 값
  • 상자 그리기 문자

 

또한 스위프트에서 제공하는 키워드 같은 경우 변수명으로 사용하지 말라고 한다.

 

자료형

 

스위프트의 기본 자료형(=원시 자료형)은 아래와 같다.

 

  • Bool
  • Int / UInt
  • Float
  • Double
  • Character
  • String
  • Any
  • AnyObject
  • nil

 

자바 / 코틀린으로 먼저 개발을 접한 내게 생소한 이름은 Bool, UInt, nil, AnyObject 정도다.

Bool이야 Boolean의 축약형이라고 생각하면 되지만 다른 값들은 생소하기 때문에 공식문서를 좀 확인해 본다.

 

https://docs.swift.org/swift-book/documentation/the-swift-programming-language/thebasics/#UInt

 

Documentation

 

docs.swift.org

스위프트는 현재 플랫폼의 기본 단어 크기와 같은 크기를 갖는 부호 없는 정수 타입인 UInt를 제공한다
- 32비트 플랫폼에서 UInt는 UInt32와 같다. 64비트 플랫폼에서 UInt는 UInt64와 크기가 같다

플랫폼의 기본 단어 크기와 같은 크기의 부호 없는 정수 타입이 특별히 필요한 경우에만 사용하라. 그게 아니라면 저장할 값이 음수가 아닌 것인 경우에도 Int가 선호된다. 정수 값에 대해 Int를 일관되게 쓰면 코드 상호 운용성이 향상되고 서로 다른 숫자 타입 간에 변환할 필요가 없고, 타입 안정성과 타입 추론에 설명된 대로 정수 타입 추론과 일치한다

 

공식문서 설명만 놓고 보면 UInt는 32비트, 64비트 플랫폼 별 각각 다른 표현 범위를 갖게 되는 듯하다.

하지만 음수가 아니라도 Int 사용을 제안하는데 UInt가 만들어진 이유는 무엇인가? 그리고 공식문서의 말대로 UInt 대신 Int만 사용해도 문제가 없는 건가?

한번 사용해 봤다.

 

print("Int8의 표현 범위 : \(Int8.min) ~ \(Int8.max)")
print("Int16의 표현 범위 : \(Int16.min) ~ \(Int16.max)")
print("Int32의 표현 범위 : \(Int32.min) ~ \(Int32.max)")
print("Int64의 표현 범위 : \(Int64.min) ~ \(Int64.max)")
print("\n")
print("UInt8의 표현 범위 : \(UInt8.min) ~ \(UInt8.max)")
print("UInt16의 표현 범위 : \(UInt16.min) ~ \(UInt16.max)")
print("UInt32의 표현 범위 : \(UInt32.min) ~ \(UInt32.max)")
print("UInt64의 표현 범위 : \(UInt64.min) ~ \(UInt64.max)")

// Int8의 표현 범위 : -128 ~ 127
// Int16의 표현 범위 : -32768 ~ 32767
// Int32의 표현 범위 : -2147483648 ~ 2147483647
// Int64의 표현 범위 : -9223372036854775808 ~ 9223372036854775807

// UInt8의 표현 범위 : 0 ~ 255
// UInt16의 표현 범위 : 0 ~ 65535
// UInt32의 표현 범위 : 0 ~ 4294967295
// UInt64의 표현 범위 : 0 ~ 18446744073709551615

 

Int를 사용하면 표현 범위가 음수~양수까지 잡히지만 UInt를 쓰면 음수를 제외한 0부터 표현 범위가 잡힌다.

음수를 사용하지 않는 범위의 정수를 표현한다면 UInt를 써도 될 듯 하지만, 개발문서 피셜대로 그냥 Int만 써도 될 것 같다. 앱 개발 과정에서 과연 UInt를 써야 하는 경우가 있을진 모르겠지만, 일단 두 자료형의 타입은 이해하고 있자.

 

스위프트의 Any는 코틀린의 Any와 같은 이름이지만, 둘은 조금 다르다.

둘의 차이를 표로 만들면 아래와 같다.

 

  스위프트의 Any 코틀린의 Any
특징 클래스, 구조체, 열거형, 기본형, 함수 타입 등 모든 타입을 포함 널이 될 수 없는 모든 타입의 최상위 타입
함수 타입은 Any로 취급될 수 없음
null(nil) 허용 여부 null을 포함하지 않음
null을 포함할 수 있다면 Any?로 표현됨
기능적 차이 타입에 종속되지 않는 유연성 제공
(동적 타입 언어의 특성을 일부 반영)
리플렉션 등 기능 사용 시 유용
모든 클래스의 기본 클래스로 취급
자바의 Object와 비슷한 역할
모든 객체가 가진 기본 메서드(equals, hashCode, toString) 제공

 

null 허용 여부를 제외하면 둘은 그렇게 큰 차이가 없어 보인다.

 

다른 키워드인 AnyObject는 Any + Object라는 2가지 단어의 합성어기 때문에 클래스 타입의 인스턴스만 나타낼 수 있다.

다만 스위프트는 Objective-C와 같이 사용할 수 있도록 호환성을 고려해 설계됐기 때문에, 클래스와 구조체 / 열거형은 서로 구분된다. 즉 구조체와 열거형은 클래스에 속하지 않으며 값 타입으로 분류되고, 참조 타입으로 분류되지 않는다.

코틀린에선 구조체라는 개념이 없으며 열거형은 enum class라는 키워드로 작성할 수 있어서 클래스의 한 형태로 취급된다. 이 정도 차이가 있지만 결론적으로 스위프트의 AnyObject를 사용한 배열이나 컬렉션이 있다면 그 배열 or 컬렉션에는 클래스 타입만 들어갈 수 있다.

아래는 AnyObject 타입의 배열에 여러 값들을 넣는 예시다.

 

var arr: [AnyObject] = []

arr.append(1)
arr.append(1.0)
arr.append("test")
arr.append(false)
arr.append(Test.init())
arr.append({ print("Hello, Swift!") })

class Test {
  var num: Int = 30
}

 

Replit에서 실행하면 결과는 아래와 같다.

 

 

하지만 Test 클래스만 넣고 다른 코드들을 없앤 다음 실행하면 아무 에러도 발생하지 않는다.

 

마지막으로 nil은 뭘까? 자바/코틀린의 null과 같은 의미인가? 왜 null이 아니라 nil이란 이름을 쓰는 건가? 궁금해서 찾아봤다.

 

https://www.quora.com/Why-does-Swift-use-nil-instead-of-null

 

Why does Swift use nil instead of null?

Answer (1 of 3): Swift uses nil because Objective-C uses nil. Objective-C uses nil because Smalltalk uses nil. And Smalltalk uses nil because most languages that don’t descend from C use nil, all the way back to Lisp. Honestly, it’s the C family that a

www.quora.com

스위프트는 타입 안전성, 선택성을 제공하는 안전하고 현대적인 언어로 설계됐기 때문에 null 대신 nil을 쓴다. nil의 사용은 값이 없음을 명시적으로 표현해서 널 포인터 예외 같은 일반적인 프로그래밍 오류를 줄이려는 스위프트의 목표와 일치한다. 이 접근 방식은 개발자가 더 안정적이고 예측 가능한 코드를 작성하는 데 도움이 된다. 또한 nil 사용은 언어의 전반적 디자인, 구문과 일치한다

 

어찌 보면 코틀린의 null과 같은 의미로 쓰이는 것 같은데, 검색해 보니 별도의 포스팅으로 써야 할 정도로 이런저런 내용이 있어서 일단 코틀린의 null과 같이 값이 없는 상태라고 이해하고 넘어간다.

반응형

'iOS > Swift' 카테고리의 다른 글

[Swift] 클래스와 구조체  (0) 2024.02.11
[Swift] 반복문 (for-in, while, repeat-while)  (0) 2024.01.17
[Swift] 조건문 (if, switch)  (0) 2024.01.15
[Swift] Swift란?  (0) 2024.01.11
Comments