4
3

More than 1 year has passed since last update.

【Swift】 String型を数値型に変換すると、Optionalになってしまう理由

Last updated at Posted at 2022-05-10

目次

はじめに
String型
数値型
Optional型
インスタンス・インスタンス化
イニシャライザ
結論

はじめに

以下のコードのように、String型を数値型に変換した際、値にOptionalが付いてしまう理由について解説したいと思います。はじめに必要な知識について簡単に説明した後、結論のほうを述べさせていただきます。

let text = "123"
let num = Int(text)
print(num) // Optional(123)

String型

"alphabet" や "アイウエオ" のような文字列を表す型をString型と言い、"abc"のように「"」(ダブルクオート)で文字列を囲むと、String型の値を生成します。

let a = "ここに文字列を入れる" // String型

数値型

Swiftにおいて数値型は、整数型と浮動小数点数型の大きく2つに分けられます。

整数型

整数型とは、その名の通り整数を表す型であり、保持できる値のビット数などによって様々な型に分類されますが、代表的な整数型はInt型であります。

浮動小数点型

浮動小数点型とは、浮動小数点方式で小数を表す数値型であり、Swiftでは主にFloat型とDouble型の2種類があります。それぞれ32ビットと64ビットの固定のビット数を持ちます。

let a = 123 // Int型
let b = 1.0 // Double型

Optional型

Optional型とは、値があるか空か(値が存在するかしないか)のいずれかを表す型であり、変数や定数が値がnilを許容する必要がある場合はOptional型を使用します。Optoinal型にしたい場合、型名の後ろに「?」を付けることでOptoinal型にする事ができます。

var a: Int
print(a) // 値が存在しないため、エラー。

var b: Int?
print(b) // nil

インスタンス・インスタンス化

インスタンスとは型を実体化したものであり、型に定義されているプロパティやメソッドを持ちます。例えば、String型の値 "abc" はString型のインスタンスであり、append(_:)メソッドなどを持ちます。

インスタンス化の方法

型をインスタンス化するには、次のように型名に( )を付けてイニシャライザを呼び出します。
( )内には、必要に応じてイニシャライザの引数を渡します。

型名()

イニシャライザ

イニシャライザは型のインスタンスを初期化します。型に定義されているすべてのプロパティはインスタンス化の完了までに値が代入されていなければならないため、プロパティの宣言時に初期値を持たないプロパティは、イニシャライザ内で初期化する必要があります。

定義方法

イニシャライザはinitキーワードで宣言し、引数と初期化に関する処理を定義します。イニシャライザの引数の文法は、関数の引数と同じです。

struct Book {
    let title: String
    let author: Stirng

    init(title: String, author: String) {
        self.title = title
        self.author = author
    }
}

let book1 = Book(title: "坊ちゃん", author: "夏目漱石") // OK

失敗可能イニシャライザ

イニシャライザはすべてのプロパティを正しい型の値で初期化する役割を果たしていますが、イニシャライザの引数によってはプロパティを初期化できないケースが出てきます。初期化に失敗する可能性があるイニシャライザは、失敗可能イニシャライザ(failable initializer)として表現でき、結果をOptional型として返します。

定義方法

失敗可能イニシャライザはinitキーワードに?を加えてinit?(引数)のように定義します。初期化の失敗はreturn nilで表し、イニシャライザはnilを返します。なお、初期化を失敗させる場合にはインスタンス化が行われないため、プロパティを未初期化のままにできます。
次の例では、Book型のプロパティtitle,authorをString型の値で初期化できなかった場合、結果をnilで返すようにしています。

struct Book {
    let title: String
    let author: String

    init?(title: Any, author: Any) {
        guard let title = title as? String,
              let author = author as? String else {
            return nil
        }
    
        self.title = title
        self.author = author
    }
}

let book1 = Book(title: "坊ちゃん", author: "夏目漱石") // OptionalのBook型になる
let book2 = Book(title: "吾輩は猫である", author: 1000) // nil

結論

文字列は必ずしも数値のフォーマットになっているとは限らず、String型から数値型への変換は失敗する可能性があリます。そのため、失敗可能イニシャライザによって初期化をしてインスタンス化を行うよう設定されているため、String型からInt型への変換を行なった場合Optionalとなってしまいます。(以下、Int型ソースコード記述)

    @inlinable public init?<S>(_ text: S, radix: Int = 10) where S : StringProtocol

    /// Creates a new integer value from the given string.
    ///
    /// The string passed as `description` may begin with a plus or minus sign
    /// character (`+` or `-`), followed by one or more numeric digits (`0-9`).
    ///
    ///     let x = Int("123")
    ///     // x == 123
    ///
    /// If `description` is in an invalid format, or if the value it denotes in
    /// base 10 is not representable, the result is `nil`. For example, the
    /// following conversions result in `nil`:
    ///
    ///     Int(" 100")                       // Includes whitespace
    ///     Int("21-50")                      // Invalid format
    ///     Int("ff6600")                     // Characters out of bounds
    ///     Int("10000000000000000000000000") // Out of range

Int型の場合だと、'+'もしくは'-'の記号と0〜9の数字のみで構成された文字列以外は、イニシャライズを失敗させてnilで返すようにされているようです。
(ちなみに、上記ソースコードのイニシャライザによってインスタンス化を行う際、引数名のtextとradixを記述する必要がない理由は、textは外部引数名を省略していて、radixはデフォルト引数を指定しているからです。)

参考

・Swift実践入門 (https://gihyo.jp/book/2020/978-4-297-11213-4)

4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3