Why doesn't this work?
"abcdefg".characters.map(String.init) // error: type of expression is ambiguous without more context
One really cool thing I like in Swift is the ability to convert a collection of one thing to another by passing in an init method (assuming an init()
for that type exists).
Here's an example converting a list of tuples to instances of ClosedInterval
.
[(1,3), (3,4), (4,5)].map(ClosedInterval.init)
That example also takes advantage of the fact that we can pass a tuple of arguments as a single argument as long as the tuple matches the function's argument list.
Here another example, this time converting a list of numbers to string instances.
(1...100).map(String.init)
Unfortunately, the next example does not work. Here I am trying to split up a string into a list of single-character strings.
"abcdefg".characters.map(String.init) // error: type of expression is ambiguous without more context
map()
should be operating on a list of Character
(and indeed I was able to verify in a playground that Swift infers the correct type of [Character] here being passed into map
).
String
definitely can be instantiated from a Character
.
let a: Character = "a"
String(a) // this works
And interestingly, this works if the characters are each in their own array.
"abcdefg".characters.map { [$0] }.map(String.init)
Or the equivalent:
let cx2: [[Character]] = [["a"], ["b"], ["c"], ["d"]]
cx2.map(String.init)
I know that I could do this:
"abcdefg".characters.map { String($0) }
But I am specifically trying to understand why "abcdefg".characters.map(String.init)
does not work (IMO this syntax is also more readable and elegant)
To initialize a Map with values, use the Map() constructor, passing it an array containing nested arrays of key-value pairs, where the first element in the array is the key and the second - the value. Each key-value pair is added to the new Map .
The Static Initializer for a Static HashMap We can also initialize the map using the double-brace syntax: Map<String, String> doubleBraceMap = new HashMap<String, String>() {{ put("key1", "value1"); put("key2", "value2"); }};
For initializing an empty Map, we'll not pass any key-value pair in this method: Map<String, String> emptyMapUsingJava9 = Map. of(); This factory method produces an immutable Map, hence we'll not be able to add, delete or modify any key-value pair.
Simplified repro:
String.init as Character -> String
// error: type of expression is ambiguous without more context
This is because String
has two initializers that accept one Character
:
init(_ c: Character)
init(stringInterpolationSegment expr: Character)
As far as I know, there is no way to disambiguate them when using the initializer as a value.
As for (1...100).map(String.init)
, String.init
is referred as Int -> String
. Although there are two initializers that accept one Int
:
init(stringInterpolationSegment expr: Int)
init<T : _SignedIntegerType>(_ v: T)
Generic type is weaker than explicit type. So the compiler choose stringInterpolationSegment:
one in this case. You can confirm that by command + click on .init
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With