在map()中使用init()

vop*_*lif 12 swift swift2

TL; DR

为什么这不起作用?

"abcdefg".characters.map(String.init) // error: type of expression is ambiguous without more context
Run Code Online (Sandbox Code Playgroud)

细节

在Swift中我喜欢的一个非常酷的东西是能够通过传入一个init方法将一个东西的集合转换为另一个东西(假设存在init()for该类型).

这是一个将元组列表转换为实例的示例ClosedInterval.

[(1,3), (3,4), (4,5)].map(ClosedInterval.init)
Run Code Online (Sandbox Code Playgroud)

这个例子还利用了这样一个事实,即只要元组与函数的参数列表匹配,我们就可以将参数元组作为单个参数传递.

这是另一个例子,这次将数字列表转换为字符串实例.

(1...100).map(String.init)
Run Code Online (Sandbox Code Playgroud)

不幸的是,下一个例子不起作用.在这里,我试图将一个字符串拆分为单字符字符串列表.

"abcdefg".characters.map(String.init) // error: type of expression is ambiguous without more context
Run Code Online (Sandbox Code Playgroud)

map()应该在一个列表上运行Character(事实上​​,我能够在游乐场中验证Swift推断出正确的[Character]类型被传递到这里map).

String绝对可以从a实例化Character.

let a: Character = "a"
String(a) // this works
Run Code Online (Sandbox Code Playgroud)

有趣的是,如果角色各自都在自己的数组中,这就有效.

"abcdefg".characters.map { [$0] }.map(String.init)
Run Code Online (Sandbox Code Playgroud)

或等效的:

let cx2: [[Character]] = [["a"], ["b"], ["c"], ["d"]]
cx2.map(String.init)
Run Code Online (Sandbox Code Playgroud)

我知道我可以这样做:

"abcdefg".characters.map { String($0) }
Run Code Online (Sandbox Code Playgroud)

但我特意试着理解为什么"abcdefg".characters.map(String.init)不起作用(IMO这种语法也更具可读性和优雅性)

rin*_*aro 14

简化repro:

String.init as Character -> String
// error: type of expression is ambiguous without more context
Run Code Online (Sandbox Code Playgroud)

这是因为String有两个接受一个的初始化器Character:

init(_ c: Character)
init(stringInterpolationSegment expr: Character)
Run Code Online (Sandbox Code Playgroud)

据我所知,当使用初始化程序作为值时,无法消除它们的歧义.

至于(1...100).map(String.init),String.init被称为Int -> String.虽然有两个初始化器接受一个Int:

init(stringInterpolationSegment expr: Int)
init<T : _SignedIntegerType>(_ v: T)
Run Code Online (Sandbox Code Playgroud)

泛型类型比显式类型.因此编译器stringInterpolationSegment:在这种情况下选择一个.您可以通过command+点击确认.init.