[Swfit] 자릿수 더하기 - Optional곁들이기

·2024년 12월 3일
0

SwiftAlgorithm

목록 보기
2/105
post-thumbnail

자릿수더하기

문제설명

자연수 N이 주어지면, N의 각 자릿수의 합을 구해서 return 하는 solution 함수를 만들어 주세요.
예를들어 N = 123이면 1 + 2 + 3 = 6을 return 하면 됩니다.

풀이

그냥 처음에는 반복문 돌리면서 , 혹은 reduce로 한번에 배열을 짤라준다음 각 원소들을 Int로 바꿔줘서 더해주면 되겠구나 싶었는데, 다음과 같은 에러가 발생했다.

error

이유인 즉슨, Array(String(n)) 을 반복문 돌려서 하나씩 볼때는 각각의 value가 Character 타입이 되는데, Character Type일때는 Int로 전환이 불가능하다는 이야기였다.


Q: Character을 Int로 못바꿔?

Swift Character->Int 관련 링크

텐서플로우 해결책

구글링을 통해 두가지 방법을 볼 수 있었는데,

첫번째 방법

Character타입의 메소드 wholeNumberValue를 사용하는 것이다.

wholeNumberValue

wholeNumberValue는 char->Int에 의도에 맞는 찰떡 메소드였다. 해당 함수는 숫자로 변환해보고 이게 문자열이라서 숫자로 변경할 수 없으면 nil을 반환한다

nil

두번째 방법

Character -> Int는 불가능하지만, String -> Int는 가능하니까 이를 활용한 직관적인 해결책이다.

  1. Character -> String
  2. String -> Int

이렇게 두 단계를 거쳐서 해줄 수 있는 해결책이다.

import Foundation
 class Solution {
    func addLocation(_ n: Int) -> Int {
        return Array(String(n)).reduce(0) {
            $0 + Int(String($1))!
        }
    }
 }
 let solution = Solution()
 print(solution.addLocation(1234))

Stirng으로 한번 묶어준 친구를 한번 더 Int로 묶어주면 정상적으로 실행이 된다.

주의점!

여기 자세히 보시면은

$0 + Int(String($1))!

!로 강제 언래핑을 해준 것을 볼 수 있다. Int(String(($1))을 !없이 수행하게 되면 이게 Optional<Int>로 되기 때문에

!를 사용한 의도

  1. 이거 nil 안나오는거로 줄게! +
  2. 안에 들어오는 String($1)는 분명 너가 올바른 값으로 반환할 수 있는 친구를 넣어줄거야!
    라고 약속한 것이라고 보시면 될 것 같다.

Q: 근데 String($1)는 괜찮은건가? 이것도 옵셔널이면 ! 두개 써줘야하는거 아닌가? Int()는 왜 !가 필요하고 String()에는 필요가 없나? 아니면 두개를 하나의 !로 퉁친건가??

라고 의문점이 들었는데 알아보니
String($1)은 단순히 Character를 문자열로 변환해주는 친구라서, Optional<Type>가 아니라 확정된 타입으로 반환해주기 때문인데,즉 크래시 될일이 없기때문에 컴파일러 입장에서도 옵셔널로 인지할 필요가 없는 것으로 판단한다.
즉 String의 반환타입은 non-optional이기 때문, 이것으로 얻은 새로운 정보는 함수에 따라 non-optional인 함수와 그렇지 않은 함수가 구분되는구나, 그것으로 인해서 이게 옵셔널로 값을 인지하는지 안하는지 알아낼 수가 있구나 싶었다.

좀 더 자세히

let stringValue = String(123)
let intValue = Int("123")
print(type(of: stringValue)) // String
print(type(of: intValue)) // Optional<Int>

보시면은 Int() 메소는 Optional 타입을 반환한다. 인자값에 사용자가 이상한 집어넣었을지 모르니 일단
문자열을 정수로 변환하는 과정에서 변환이 실패할 수 있기 때문에 Optional<Int> 타입을 반환하기로한 optional함수인것이다. 언제든지 nil을 반환할 수 있게끔, nil이 떠도 괜찮게 Optional을 고수하고 있다.
컴파일값

때문에 아래처럼 !로 Optional 안쓸래! 해버린다는 것의 의미는

컴파일러에게 나는 Int()잘 굴러가게 제공할게~
개발자인 우리가 컴파일러에게 이 값은 nil이 리턴되지 않게끔 내가 잘 약속 지킬게!라고 보증하는 것이다.

라고 선언한다고 보시면 이해하기 쉽다. 그런데 배신하고!하면서 Int()안에 "ABC"같이 소화하지 못하는 파라미터를 넣어주면 이제 에러가 발생할 것이다.
Error


대신, 이렇게 약속을 잘지키면 아래처럼

let optionalValue = Int("123)
let intValue = Int("123")!
print(type(of: optionalValue)) // Optional<Int>
print(type(of: intValue)) // Int

!를 붙여줬으면 그냥 Int값으로 Swift가 보답을 해줄것이다..


Q: 그럼 String() 왜 Optional타입을 반환하지않는 non-optional 함수야? 얘는 터질일이 없나?

놀랍게도..!

String()변환은 일반적으로 실패할 가능성이 없다고한다. 어떤 타입이던지 잘 String()으로 반환될 수 있기 때문에 강제언래핑 같은 거를 활용하지 않더라도 이거는 그냥 확실하게 String으로 나오는것이다. Optional<String> 이렇게 반환되지 않는다. 그래서 non-optional 이고, 언래핑이 필요하지 않다.

예시

let emptyString = String() // ""  nil대신 그냥 빈문자열이 반환됨
let stringFromInt = String(123) // "123"
let stringFromChar = String("A") // "A"
let stringFromArr = String([1,2,3]) // "[1,2,3]" 배열마저 이렇게 문자열로 잘 바뀜

결론적으로

import Foundation
 class Solution {
    func addLocation(_ n: Int) -> Int {
        return Array(String(n)).reduce(0) {
            $0 + Int(String($1))!
        }
    }
 }
 let solution = Solution()
 print(solution.addLocation(1234))

따라서 String($1)은 옵셔널이 아니므로 강제 언래핑(!)이 필요 없기때문에 Int()에 해당하는 언래핑 ! 한번으로 해결되는 것을 확인할 수 있었습니다!

정답

느낀점

엄청나게 쉬운 응애 문제였는데, 모든게 좀 새로워서 정리하느라 좀 시간을 많이 잡아먹은 것 같다. 이번에 Optional에 대해서 좀 맛보기처럼 알아봤는데, 이제 다음에는 Optional관련해서 좀 더 길게 포스팅을 해봐야겠다고 생각을 했다. (블로그 뒤적이면서 얻은 정보는, swift의 Optional이 C언어의 포인터처럼 swift의 핵심격으로 취급되는것 같더라. 원래 헷갈리는 개념이구나를 알게되었고, 좀 더 깊게 해봐야할 것 같다.

profile
기억보단 기록을

0개의 댓글