SwiftでDictionary型のリテラルを定義した時にType of expression is ambiguous without more contextのエラーが出る問題

SwiftでDictionary型のリテラルを定義した時にType of expression is ambiguous without more contextのエラーが出る問題

検証環境

  • Swift 2.1.1
  • XCode 7.2.1

色々な型が入れ子になったDictionaryのリテラルを定義すると、「Type of expression is ambiguous without more context」等のエラーが出る場合があります

ambiguous=不明瞭な ということなので型を定義すれば解決できます。

なぜエラーになっているか

エラーになっている原因は、エラーメッセージにもあるように型が不明確で型推論ができないということになります。

以下のパターンでは型推論が働いて、型を指定しなくても入れ子にすることができます。

let parameters = [
    "user_id" : "user01",
    "password": "password",
    "options": [
        "role": "admin",
        "positioin": [
            "lat": "35.20202020",
            "lng": "108.1019191"
        ]
    ]
]

このような場合、型推論により[String:String]のDictionayと認識され、問題なくコンパイルが通ります。

以下はオプショナル型のデータが混ざっている例ですが、型推論ができず「'(dictionaryLiteral: (NSCopying: AnyObject), (NSCopying, AnyObject))’ is not convertible to ‘(dictionaryLiteral: (NSString: NSString)…)’ tuples have a diffirent number of element」のエラーによりコンパイルが通りません。

var password: String?

let parameters = [
    "user_id" : "user01",
    "password": password,
    "options": [
        "role": "admin",
        "positioin": [
            "lat": "35.20202020",
            "lng": "108.1019191"
        ]
    ]
]

XCodeはpositionのキーのあたりをエラーとして表示します。

上記の例の場合はpasswordをセットする前にアンラップするか、Dictionaryの型をオプショナルにすることで解決できます。

アンラップで対応する場合

var password: String?
password = "password"
let parameters = [
    "user_id" : "user01",
    "password": password!,
    "options": [
        "role": "admin",
        "positioin": [
            "lat": "35.20202020",
            "lng": "108.1019191"
        ]
    ]
]

この場合、passwordには値が代入されている必要があります。

型を指定する場合

var password: String?

let parameters: [String: AnyObject?] = [
    "user_id" : "user01",
    "password": password,
    "options": [
        "role": "admin",
        "positioin": [
            "lat": "35.20202020",
            "lng": "108.1019191"
        ]
    ]
]

positionキーにDictionaryが入っているので`AnyObject?’を指定しています。

ネストが深い複雑なデータの例

以下のようにネストが深いと、どこがエラーになっているのかすぐにわからずコンパイルエラーの解決に時間がかかることがあります。
以下の例では、値の型をAnyObjectにしているのにエラーになっている箇所があります。

import Foundation

let role = "admin"
var userId = "100100100"
var password: String?
var position: [String:Double]? = [
    "lat": 3.019209191,
    "lng": 108.0201991
]

var options: [String: AnyObject?]? = [
    "role": role,
    "position": position
]

let parameters: [String: Any?] = [
    "user_id" : userId,
    "password": password,
    "options": options
]

この場合、parametersの値の型をAnyObjectからAnyのオプショナル型にすることで解決できます。

なぜAnyだと解決できるのかについては次回にでも。

TAG

  • このエントリーをはてなブックマークに追加
金子 将範
エンジニア 金子 将範 rubyist

新しいことや難しい課題に挑戦することにやりがいを感じ、安定やぬるい事は退屈だと感じます。 考えるより先に手が動く、肉体派エンジニアで座右の銘は諸行無常。 大事なのは感性、プログラミングにおいても感覚で理解し、感覚で書きます。