SwiftでFunction、Method、Initializer、Propertyなどを呼び出した際に、Xcodeへ次のようなErrorが表示されることがあります。
Ambiguous use of 'show'
または:
Ambiguous use of 'init'
このErrorは、Compilerから見て複数のDeclarationやOverloadが同時に候補となり、どれを使うべきか1つに決められない場合に発生します。
代表的な原因は、似たFunction Overloadが複数存在する、LiteralのTypeを決められない、ClosureのParameterやReturn Typeが曖昧、Generic Typeを推論できない、同名Methodが複数のProtocol Extensionから提供されている、SwiftUIのInitializer Candidateが複数残っている、といったものです。
解決の基本は、Compilerが候補を1つに絞れるように、Argument Type、Return Type、Closure Type、Generic Typeなどの情報を明示することです。
- 「Ambiguous use of」とは
- 「Invalid redeclaration」との違い
- 代表的な発生状況
- 主な原因
- 1. Overloadが多く、Argumentだけでは区別できない
- 2. Numeric LiteralのTypeが曖昧
- 3. nilだけを渡している
- 4. 空Arrayだけを渡している
- 5. Function ReferenceがOverloadされている
- 6. mapへOverloadされたFunctionを直接渡している
- 7. Closure Parameter Typeが曖昧
- 8. Closure Return Typeが曖昧
- 9. Generic Parameterを十分に推論できない
- 10. Optional版とNon-Optional版のOverloadがある
- 11. Protocol Extensionに同名Methodがある
- 12. Protocol RequirementとExtension Methodが競合している
- 13. 複数Moduleに同名FunctionやTypeがある
- 14. SwiftUIのInitializerが多数ある
- 15. SwiftUIでBindingとValueを取り違えている
- 16. Pickerのselectionとtag Typeが曖昧
- 17. Generic Initializerが複数ある
- 18. ExpressibleBy…系ProtocolによるLiteral推論が複雑
- 19. Default ArgumentがあるOverload同士が似すぎている
- 20. Error箇所以外のType Errorが原因
- まず確認すること
- 解決方法1:VariableへType Annotationを付ける
- 解決方法2:Argumentを明示的にCastする
- 解決方法3:nilへOptional Typeを付ける
- 解決方法4:空ArrayへElement Typeを付ける
- 解決方法5:Function ReferenceへFunction Typeを付ける
- 解決方法6:ClosureでOverloadを明示する
- 解決方法7:Closure Parameter Typeを明示する
- 解決方法8:Closure Return Typeを明示する
- 解決方法9:mapのResult Typeを明示する
- 解決方法10:compactMapのReturn Typeを明示する
- 解決方法11:Generic Typeを明示する
- 解決方法12:Generic FunctionのReturn Typeを明示する
- 解決方法13:Overloadを減らす
- 解決方法14:Default Argumentが競合するOverloadを整理する
- 解決方法15:Optional Overloadを整理する
- 解決方法16:Protocol Extensionの競合を解消する
- 解決方法17:Module名を明示する
- 解決方法18:同名Functionの参照先をWrapperで分ける
- 解決方法19:Initializerを明示的に選択する
- 解決方法20:SwiftUIでBindingを正しく渡す
- 解決方法21:SwiftUI Custom ViewのBindingを確認する
- 解決方法22:SwiftUI PickerのTypeを揃える
- 解決方法23:SwiftUIのOptionalを先にUnwrapする
- 解決方法24:SwiftUIの複雑なViewを分割する
- 解決方法25:複雑なExpressionを途中Variableへ分割する
- 解決方法26:Numeric Typeを明示する
- 解決方法27:CGFloatやDoubleへ明示的に変換する
- 解決方法28:Function Name自体を分ける
- 解決方法29:Call Siteから不要なType Conversionを減らす
- 解決方法30:APIのDeclaration側を見直す
- 「Ambiguous use of init」と表示される場合
- 「Ambiguous use of subscript」と表示される場合
- 「Ambiguous use of operator」と表示される場合
- SwiftUIで発生する場合
- mapやcompactMapで発生する場合
- Protocol Extensionで発生する場合
- 複数Moduleで同名Typeがある場合
- Clean Build Folderで直るか
- DerivedData削除は必要か
- やってはいけない対処
- 最短で確認するチェックリスト
- まとめ
「Ambiguous use of」とは
ambiguousは「曖昧」という意味です。
Swiftでは、同じ名前のFunctionをParameter TypeなどによってOverloadできます。
例えば:
func show(_ value: Int) { print("Int: \(value)") }
func show(_ value: Double) {
print("Double: (value)")
}
次のCallなら:
show(10)
通常はLiteralのContextから適切な候補を選択できます。
しかし、より複雑なGeneric、Closure、Numeric Typeなどが絡むと、複数Candidateが同程度に適合して1つへ決められないことがあります。
その結果:
Ambiguous use of 'show'
と表示されます。
「Invalid redeclaration」との違い
前項の:
Invalid redeclaration of 'show'
は、Compilerから見て同じDeclarationを重複して定義しているErrorです。
一方:
Ambiguous use of 'show'
は、複数のDeclaration自体は有効でも、Call Siteからどれを選べばよいか決められないErrorです。
ポイント:Invalid redeclarationはDeclaration側の重複、Ambiguous useは主にCall Siteでの候補選択の曖昧さです。
代表的な発生状況
- 同名FunctionのOverloadが複数ある
- Initializer Candidateが複数ある
- Numeric LiteralのTypeを決められない
- nilだけではOptionalのWrapped Typeが分からない
- 空ArrayやDictionaryのElement Typeが不明
- Closure Parameter Typeを推論できない
- Closure Return Typeを推論できない
- map・compactMapなどで複数のFunction Referenceが候補になる
- Generic FunctionのType Parameterを決められない
- Protocol Extensionの同名Methodが複数候補になる
- 同名TypeやFunctionを複数ModuleからImportしている
- SwiftUIの複数Initializer Candidateが残っている
- Bindingと通常Valueの違いでInitializer選択が曖昧になる
- OptionalとNon-OptionalのOverloadが両方ある
主な原因
1. Overloadが多く、Argumentだけでは区別できない
例えば:
func process(_ value: Int) { }
func process(_ value: Double) {
}
別のGeneric Expressionを経由すると、IntとDoubleのどちらにすべきか判断できない場合があります。
2. Numeric LiteralのTypeが曖昧
Swiftの整数Literalや浮動小数点LiteralはContextに応じてConcrete Typeが決まります。
Contextが不足すると複数のNumeric Overloadが候補になります。
3. nilだけを渡している
func setValue(_ value: String?) { }
func setValue(_ value: Int?) {
}
setValue(nil)
nilだけではString?なのかInt?なのか判断できません。
4. 空Arrayだけを渡している
func process(_ values: [String]) { }
func process(_ values: [Int]) {
}
process([])
空ArrayにはElement Typeの情報がないため、どちらもCandidateになります。
5. Function ReferenceがOverloadされている
func convert(_ value: Int) -> String { String(value) }
func convert(_ value: Double) -> String {
String(value)
}
let handler = convert
handlerのFunction Typeがないため、どちらのconvertか決められません。
6. mapへOverloadされたFunctionを直接渡している
let values = numbers.map(String.init)
InitializerやFunctionに多くのOverloadがある場合、Input TypeやOutput Typeによっては候補を1つへ絞れないことがあります。
7. Closure Parameter Typeが曖昧
someMethod { value in print(value) }
呼び出すGeneric APIやOverloadによってはvalueのTypeを決定できない場合があります。
8. Closure Return Typeが曖昧
複数Branchで異なるTypeを返していたり、nilのみを返していたりすると、Output Typeを決められない場合があります。
9. Generic Parameterを十分に推論できない
func make<T>() -> T { fatalError() }
let value = make()
この場合は「Generic parameter could not be inferred」と表示されることもありますが、周囲のOverload状況によってAmbiguous useへつながることがあります。
10. Optional版とNon-Optional版のOverloadがある
例えば:
func show(_ value: String) { }
func show(_ value: String?) {
}
Call ContextによってはOptional Promotionなどが絡み、候補の判定が分かりにくくなる場合があります。
11. Protocol Extensionに同名Methodがある
複数Protocolから同名Methodが提供されると、Concrete Type側でどちらを使うべきか曖昧になることがあります。
12. Protocol RequirementとExtension Methodが競合している
Protocol設計やConditional Extensionが複雑になると、同名MemberのCandidateが増えることがあります。
13. 複数Moduleに同名FunctionやTypeがある
例えば2つのFrameworkをImportし、両方に同名Typeが存在する場合です。
14. SwiftUIのInitializerが多数ある
Text、Button、TextField、PickerなどSwiftUIのViewには複数のGeneric Initializerがあります。
Argument TypeやBinding Typeが不足すると、Compilerが候補を絞れないことがあります。
15. SwiftUIでBindingとValueを取り違えている
@State private var name = ""
nameはString、$nameはBinding<String>です。
適切なInitializer Candidateを選ぶために、要求される方を渡す必要があります。
16. Pickerのselectionとtag Typeが曖昧
selectionとtagのTypeが一致しない、またはtagにType Contextがない場合、Generic Candidate Resolutionが失敗することがあります。
17. Generic Initializerが複数ある
同じTypeにConditional InitializerやProtocol Constraint付きInitializerが複数存在する場合です。
18. ExpressibleBy…系ProtocolによるLiteral推論が複雑
独自TypeがInteger LiteralやString Literalに対応している場合、Standard TypeとのCandidateが増えることがあります。
19. Default ArgumentがあるOverload同士が似すぎている
Default Argumentによって、複数のFunctionが同じCall Patternで呼べてしまうとAmbiguousになることがあります。
20. Error箇所以外のType Errorが原因
SwiftUIや複雑なGeneric Expressionでは、内部の別ErrorによってCompilerが正常に候補を絞れず、外側にAmbiguous useが表示されることがあります。
まず確認すること
1. Xcodeが示している名前を確認する
例えば:
Ambiguous use of 'init'
なら、どのInitializerを呼んでいる箇所か確認します。
Functionなら:
Ambiguous use of 'load'
などになります。
2. XcodeのAutocompleteで候補を見る
FunctionやInitializer名を入力し直して、利用できるOverloadを確認します。
同じ名前で似たSignatureが複数出ている場合、その違いを比較してください。
3. Option-clickやJump to DefinitionでDeclarationを見る
Parameter Type、Argument Label、Generic Constraintなどを確認します。
4. 最初のCompiler Errorを確認する
Ambiguous useが二次的なDiagnosticの可能性もあります。
重要:特にSwiftUIでは、Ambiguous useより前に表示されているBinding、Optional、Argument Label、Generic ParameterなどのErrorを先に修正すると解決することがあります。
解決方法1:VariableへType Annotationを付ける
Typeが曖昧なら、最も簡単な方法はConcrete Typeを明示することです。
let value: Int = 10
これによりInt向けのOverloadを選びやすくなります。
解決方法2:Argumentを明示的にCastする
例えば:
show(10 as Int)
または:
show(10.0 as Double)
とします。
注意:Castは目的のTypeが明確な場合に使います。Errorを消すためだけに無理なCastを追加するのは避けてください。
解決方法3:nilへOptional Typeを付ける
問題:
setValue(nil)
修正:
setValue( nil as String? )
または:
let value: String? = nil setValue(value)
解決方法4:空ArrayへElement Typeを付ける
問題:
process([])
修正:
process( [] as [String] )
または:
let values: [String] = [] process(values)
解決方法5:Function ReferenceへFunction Typeを付ける
func convert(_ value: Int) -> String { String(value) }
func convert(_ value: Double) -> String {
String(value)
}
let handler: (Int) -> String = convert
これでInt版のconvertを選択できます。
解決方法6:ClosureでOverloadを明示する
Function Referenceだけでは曖昧なら:
let strings = numbers.map { value in String(value) }
とClosureへ書き直します。
CompilerがInput TypeをContextから判断しやすくなります。
解決方法7:Closure Parameter Typeを明示する
let result = values.map { (value: Int) in
String(value)
}
解決方法8:Closure Return Typeを明示する
let result = values.map { (value: Int) -> String in
String(value)
}
解決方法9:mapのResult Typeを明示する
let strings: [String] = numbers.map { value in String(value) }
Output Typeを与えることでOverload Candidateを絞れます。
解決方法10:compactMapのReturn Typeを明示する
let numbers: [Int] = strings.compactMap { (text: String) -> Int? in
Int(text)
}
解決方法11:Generic Typeを明示する
例えばGeneric Containerなら:
let box: Box<String> = Box(value: nil)
のようにConcrete Typeを指定します。
解決方法12:Generic FunctionのReturn Typeを明示する
func makeValue<T>() -> T { fatalError() }
let value: User = makeValue()
TがUserと確定します。
解決方法13:Overloadを減らす
似たFunctionが多すぎる場合、API Design自体を単純化する方法があります。
例えば:
func load(id: Int) { }
func load(name: String) {
}
を:
func loadUser(id: Int) { }
func loadUser(name: String) {
}
のようにしてもよいですが、さらに意図を分けるなら:
func loadUserByID(_ id: Int) { }
func loadUserByName(_ name: String) {
}
とするとCall Siteの意味がより明確になります。
解決方法14:Default Argumentが競合するOverloadを整理する
例えば:
func show( value: Int, animated: Bool = true ) { }
func show(
value: Int,
highlighted: Bool = false
) {
}
のように、どちらも:
show(value: 10)
で呼べる設計は曖昧になります。
Function NameやRequired Parameterを分けてください。
解決方法15:Optional Overloadを整理する
例えば:
func show(_ value: String) { }
func show(_ value: String?) {
}
のように似たOverloadが本当に必要か確認します。
1つのOptional版だけで処理できる場合は、APIを統合した方が分かりやすい場合があります。
解決方法16:Protocol Extensionの競合を解消する
複数Protocolで同名Methodが定義されている場合、Concrete Typeへ明示的なMethodを実装して挙動を決めます。
protocol A { }
protocol B {
}
extension A {
func run() {
print("A")
}
}
extension B {
func run() {
print("B")
}
}
struct Worker: A, B {
func run() {
print("Worker")
}
}
Worker側の実装によって曖昧さを解消できます。
解決方法17:Module名を明示する
複数Moduleに同名Typeがある場合:
FrameworkA.User
や:
FrameworkB.User
のようにModuleを明示します。
解決方法18:同名Functionの参照先をWrapperで分ける
外部Frameworkの同名Functionを直接使うと分かりにくい場合、App側で明確なWrapper Functionを作る方法があります。
func loadLocalUser( id: Int ) { LocalSDK.load(id: id) }
解決方法19:Initializerを明示的に選択する
Initializer Overloadが多い場合、Argument LabelとTypeをすべて明示します。
let value = SomeType( text: "Hello", count: 10 )
曖昧なLiteralにはType Annotationも追加します。
解決方法20:SwiftUIでBindingを正しく渡す
例えば:
@State private var name = ""
TextField(
"Name",
text: $name
)
Bindingを要求するInitializerでは$nameを使います。
解決方法21:SwiftUI Custom ViewのBindingを確認する
struct EditView: View { @Binding var text: String
var body: some View {
TextField(
"Text",
text: $text
)
}
}
struct ContentView: View {
@State private var text = ""
var body: some View {
EditView(
text: $text
)
}
}
解決方法22:SwiftUI PickerのTypeを揃える
@State private var selected = 0
Picker(
"Option",
selection: $selected
) {
Text("One").tag(0)
Text("Two").tag(1)
}
selectionがIntならtagもIntにします。
解決方法23:SwiftUIのOptionalを先にUnwrapする
if let selectedUser { UserView( user: selectedUser ) }
Optionalをそのまま複数CandidateのあるInitializerへ渡すと分かりにくいErrorになることがあります。
解決方法24:SwiftUIの複雑なViewを分割する
巨大なbodyではType Inference Errorが外側のViewへ波及することがあります。
var body: some View { VStack { headerView contentView } }
private var contentView: some View {
UserListView(
users: users
)
}
Sub ViewやComputed Viewへ分割すると原因を特定しやすくなります。
解決方法25:複雑なExpressionを途中Variableへ分割する
例えば:
let result = users .map { $0.age } .map(String.init)
で曖昧なら:
let ages: [Int] = users.map { user in user.age }
let result: [String] =
ages.map { age in
String(age)
}
と分割します。
解決方法26:Numeric Typeを明示する
例えば:
let width: Double = 10 let count: Int = 10
Numeric APIで曖昧さが出る場合、Int、Double、CGFloatなどを明示します。
解決方法27:CGFloatやDoubleへ明示的に変換する
let count = 10
let width: CGFloat =
CGFloat(count)
Graphics関連APIではConcrete Numeric Typeを明示すると候補を絞りやすくなります。
解決方法28:Function Name自体を分ける
Overload Resolutionに頼りすぎるAPIなら:
func formatDate( _ value: Date ) -> String { ... }
func formatNumber(
_ value: Double
) -> String {
...
}
のように役割ごとに名前を分ける方が分かりやすいことがあります。
解決方法29:Call Siteから不要なType Conversionを減らす
Nested CastやOptional Transformationが多いと、CompilerのType Inferenceが複雑になります。
変換処理をIntermediate VariableやHelper Functionへ分離してください。
解決方法30:APIのDeclaration側を見直す
自作APIでAmbiguous useが頻発する場合、Call SiteだけでなくOverload Design自体を改善します。
特に:
- 同じParameter TypeでLabelだけが微妙に違う
- Default Argumentで複数Overloadが同じCall Patternになる
- Optional版とNon-Optional版が多数ある
- Generic Constraintが複雑すぎる
といった構成は見直す価値があります。
「Ambiguous use of init」と表示される場合
Initializer Candidateが複数残っています。
例えば:
let value = SomeType( value: nil )
でInitializerが:
init(value: String?) init(value: Int?)
の両方存在するなら、nilだけでは選べません。
修正:
let value = SomeType( value: nil as String? )
「Ambiguous use of subscript」と表示される場合
CollectionやCustom Subscriptに複数Candidateがある可能性があります。
Index Type、Key Type、Result Typeを確認してください。
例えばDictionaryなら:
let dictionary: [String: Int] = [ "one": 1 ]
let value: Int? =
dictionary["one"]
のようにType Contextを明示すると原因を切り分けやすくなります。
「Ambiguous use of operator」と表示される場合
OperatorもOverloadされています。
例えばNumeric Typeが混在している場合:
let intValue: Int = 10 let doubleValue: Double = 20
let result =
Double(intValue) + doubleValue
のように同じTypeへ揃えます。
SwiftUIで発生する場合
SwiftUIではGeneric InitializerやViewBuilderによるType Inferenceが多いため、Ambiguous useが二次的に出ることがあります。
確認順:
- Ambiguous useより前のErrorを確認する
- 使用中ViewのInitializer Candidateを確認する
- Argument Labelを確認する
- Argument Typeを確認する
- @Bindingと通常Valueを確認する
- Optionalを確認する
- Pickerのselectionとtagを確認する
- Closure Parameter Typeを確認する
- 複雑なbodyをSub Viewへ分割する
mapやcompactMapで発生する場合
Function ReferenceをClosureへ置き換えると解決しやすくなります。
例えば:
let strings: [String] = numbers.map { value in String(value) }
compactMapなら:
let numbers: [Int] = strings.compactMap { text in Int(text) }
Protocol Extensionで発生する場合
複数Protocol Extensionが同名Methodを提供しているなら、Concrete Type側で実装を追加して挙動を明示します。
struct Worker: A, B { func run() { print("Worker") } }
複数Moduleで同名Typeがある場合
例えば:
FrameworkA.Configuration
と:
FrameworkB.Configuration
を明示的に区別します。
Clean Build Folderで直るか
通常、このErrorはSource Code上のOverload ResolutionやType Inferenceが原因なので、Clean Build Folderでは解決しません。
補助的に:
Product → Clean Build Folder
を試すことはできますが、曖昧なCodeそのものは修正する必要があります。
DerivedData削除は必要か
XcodeのIndexが不自然な場合の補助策として:
rm -rf ~/Library/Developer/Xcode/DerivedData/*
を使うことはあります。
ただし、複数Overloadが本当に同時に適合している場合、DerivedDataを削除してもAmbiguous useは解決しません。
注意:このErrorではCache削除より、まずOverload CandidateとType Contextの確認を優先してください。
やってはいけない対処
Ambiguous useを消すためだけに、意味を考えず大量のas!やAnyを追加するのは避けてください。
Compilerが必要としているのは、「どのType・どのOverloadを使いたいのか」という明確な情報です。
Forced Castで無理に候補を絞ると、Runtime CrashやType Safety低下につながる可能性があります。
Variable Type、Argument Type、Closure Typeなど、安全なType Annotationから追加してください。
最短で確認するチェックリスト
- Ambiguous useと表示されたFunction・Method・Initializer名を確認する
- XcodeのAutocompleteで利用可能なOverloadを確認する
- Argument Labelを比較する
- Argument Typeを比較する
- Return Typeを明示してみる
- Numeric LiteralへConcrete Typeを付ける
- nilへOptional Typeを付ける
- 空Array・DictionaryへElement Typeを付ける
- Function ReferenceへFunction Typeを付ける
- Closure Parameter Typeを明示する
- Closure Return Typeを明示する
- Generic Type Parameterを明示する
- Protocol Extensionの同名Methodを確認する
- 複数Moduleの同名Typeを確認する
- SwiftUIならBinding・Optional・Initializer Candidateを確認する
まとめ
Swiftの「Ambiguous use of」は、Compilerが複数のFunction、Method、Initializer、PropertyなどのCandidateから1つを選べない場合に発生します。
代表的な原因は、似たOverload、Numeric Literal、nil、空Collection、Function Reference、Closure、Generic Type、Protocol Extension、複数Moduleの同名Declaration、SwiftUIの複数Initializer Candidateなどです。
最も基本的な解決方法は、VariableやArgument、Return Value、ClosureへConcrete Typeを明示し、Compilerが候補を1つへ絞れるようにすることです。
nilならOptional Type、空CollectionならElement Type、Function ReferenceならFunction Type、Generic APIならType ParameterまたはReturn Typeを与えてください。
SwiftUIでは、@Bindingと通常Value、Optional、PickerのSelection Type、Custom ViewのInitializerなども確認します。
自作APIでAmbiguous useが頻発する場合は、Call Siteの修正だけでなく、OverloadやDefault Argumentの設計自体を単純化すると、より安全で読みやすいSwift Codeになります。
