Reputation: 18995
I can write some short and valid example of code:
var array = ["one","two"];
var name = array[0];
All is ok. No errors. name
now contains one
.
Now suppose I write:
var array = ["one","two"];
var name = array["0"];
It will be a error, and its clear why: array is not a dictionary and I should access it contents by index.
But why does error say that "Type Int
does not conform to protocol ExtendedGraphemeClusterLiteralConvertible
?
Why Int
, if it is [String]
?
var array = ["one":0,"two":1];
var name = array[0];
It is clear: "type DictionaryIndex<String, Int>
does not conform to protocol IntegerLiteralConvertible
"
Upvotes: 0
Views: 317
Reputation: 51911
subscript
of Array
declared as:
struct Array<T> : MutableCollectionType, Sliceable {
//...
subscript (index: Int) -> T
It expect Int
as index. then if you do:
array["0"]
It's wrong, because "0"
is not Int
. But, in other words, if "0"
can be Int
, it will be OK.
Here, "0"
is what in Swift? it's string, but actually it is ExtendedGraphemeClusterLiteral
. Swift has 2 string literal types, ExtendedGraphemeClusterLiteral
and StringLiteral
.
""
empty → StringLiteral"A"
just one character → ExtendedGraphemeClusterLiteral"AB"
two or more characters → StringLiteralAnyway, try this on Playground:
extension Int: ExtendedGraphemeClusterLiteralConvertible {
typealias ExtendedGraphemeClusterLiteralType = String
public init(unicodeScalarLiteral value: String) {
self = value.toInt() ?? 0
}
public init(extendedGraphemeClusterLiteral value: String) {
self = value.toInt() ?? 0
}
}
var array = ["one","two"];
var name = array["0"]; // -> "one"
"Type 'Int' does not conform to protocol 'ExtendedGraphemeClusterLiteralConvertible'" means...
compiler: "If Int
conforms to ExtendedGraphemeClusterLiteralConvertible
, I can compile this!"
Upvotes: 1
Reputation: 93276
That error message is because you are supplying a string literal, not an instance of the String
type, where the compiler is expecting an Int
(since that's what Array
's subscript method accepts). The way the compiler would convert a string literal to an instance of type Int
is to use a method in the StringLiteralConvertible
or ExtendedGraphemeClusterLiteralConvertible
protocols, so it checks to see if the Int
type conforms to one of those. Since Int
doesn't conform, you get the error message you're seeing.
This explains Daniel T's additional information:
var array = ["one","two"]
array["0"] // trying to convert string literal to Int
var foo: Int = "0" // trying to convert string literal to Int
var index = "0"
array[index] // trying to convert String instance to Int
Likewise, your final example shows the compiler attempting the same thing—trying to convert an integer literal to an instance of DictionaryIndex<String, Int>
, because a Dictionary
instance's subscript can be passed either an instance of that dictionary's Key
type or a DictionaryIndex<Key, Value>
.
Upvotes: 2
Reputation: 33967
Interestingly, if you do this:
var array = ["one","two"];
var index = "0"
var name = array[index];
The error will be 'String' is not convertible to 'Int'
.
I think this happens because the system attempts to convert "0"
into an Int which means doing a lot of protocol checks. Array's index type is convertible to Self.Index which is a ForwardIndexType... Well, things get weird.
Whereas Swift has strong rules against implicit variable type conversion. So if you use a variable as an index, it is more clear.
Note that var foo: Int = "0"
produces the same error as your array["0"]
.
Upvotes: 0