枚举中的 CustomStringConvertible
CustomStringConvertible in enum
我在 class 中有以下枚举。
enum Attributes: String, CustomStringConvertible {
case eventDate
case eventName
case eventType
case country
var description: String {
return self.rawValue
}
}
当我尝试使用以下代码时,编译器报错如下。
var attributesList: [String] {
return [
Attributes.eventDate, //<-- Compiler error on this row
Attributes.eventName,
Attributes.eventType,
Attributes.country]
}
Cannot convert value of the type 'Attributes' to expected element type 'String'
"CustomStringConvertible" 协议 return 不应该 "description" 吗?
上面的代码有什么问题?
TL;DR - 它不起作用,因为 Attribute
的数组不能分配给 String
的数组,它们是两种不匹配的类型,并且 Swift 不会在 类型之间进行自动转换 ,需要指定显式转换。
在 Swift 中,当您使用数组文字初始化数组时,会发生以下情况:
let words = ["hello", "world"]
- 编译器识别出数组文字被分配给名为
words
的变量。由于我们没有指定 words
的类型,因此隐含地假设了一个数组。数组底层元素的类型根据数组文字的内容确定。
- 在这种情况下,数组文字是
String
类型的集合;这很容易被编译器理解
- 由于 LHS 类型是一个数组,RHS 结构是一个数组文字,并且由于 LHS 类型 (
Array
) 符合名为 ExpressibleByArrayLiteral
的预定义协议,该协议具有关联类型约束以匹配 Element
,编译器实际上会将我们的行转换为以下
示例:
let words = [String].init(arrayLiteral: ["hello", "world"]) // we do not call this init directly
这就是使用数组文字进行初始化的方式。在上面的示例中,由于我们没有指定数组的类型,因此隐式类型设置将起作用。如果我们指定了不匹配的类型,赋值将失败,因为 ExpressibleByArrayLiteral
需要关联的 Element
数组文字类型和您要分配给的实际数组匹配。
因此以下失败:
let words:[String] = [1, 2] // array literal has Element=Int, array has Element=String
这也表明Int
和String
之间没有隐式类型转换,即使Int
符合CustomStringConvertible
。
在你的例子中,你试图将一个由 Attributes
组成的数组文字分配给一个 String
的数组。这是类型不匹配。这就是它失败的原因。
如果您声明协议一致性,则以下行将起作用:
var attributesList: [CustomStringConvertible] {
return [
Attributes.eventDate,
Attributes.eventName,
Attributes.eventType,
Attributes.country
]
}
// note that we have an array of CustomStringConvertible protocol,
// each element here is still of Attributes type
// a type conforming to a protocol can be cast to an instance
// of that protocol automatically
// The above initialisation works simply because the following
// also works without any further action required
// let a:CustomStringConvertible = Attributes.country
如果您真的想要一个字符串值列表,您需要将其显式映射到一个字符串:
var attributesList1: [String] {
return [
Attributes.eventDate,
Attributes.eventName,
Attributes.eventType,
Attributes.country
].map { [=14=].description }
}
var attributesList2: [String] {
return [
Attributes.eventDate.description,
Attributes.eventName.description,
Attributes.eventType.description,
Attributes.country.description
]
}
我在 class 中有以下枚举。
enum Attributes: String, CustomStringConvertible {
case eventDate
case eventName
case eventType
case country
var description: String {
return self.rawValue
}
}
当我尝试使用以下代码时,编译器报错如下。
var attributesList: [String] {
return [
Attributes.eventDate, //<-- Compiler error on this row
Attributes.eventName,
Attributes.eventType,
Attributes.country]
}
Cannot convert value of the type 'Attributes' to expected element type 'String'
"CustomStringConvertible" 协议 return 不应该 "description" 吗? 上面的代码有什么问题?
TL;DR - 它不起作用,因为 Attribute
的数组不能分配给 String
的数组,它们是两种不匹配的类型,并且 Swift 不会在 类型之间进行自动转换 ,需要指定显式转换。
在 Swift 中,当您使用数组文字初始化数组时,会发生以下情况:
let words = ["hello", "world"]
- 编译器识别出数组文字被分配给名为
words
的变量。由于我们没有指定words
的类型,因此隐含地假设了一个数组。数组底层元素的类型根据数组文字的内容确定。 - 在这种情况下,数组文字是
String
类型的集合;这很容易被编译器理解 - 由于 LHS 类型是一个数组,RHS 结构是一个数组文字,并且由于 LHS 类型 (
Array
) 符合名为ExpressibleByArrayLiteral
的预定义协议,该协议具有关联类型约束以匹配Element
,编译器实际上会将我们的行转换为以下
示例:
let words = [String].init(arrayLiteral: ["hello", "world"]) // we do not call this init directly
这就是使用数组文字进行初始化的方式。在上面的示例中,由于我们没有指定数组的类型,因此隐式类型设置将起作用。如果我们指定了不匹配的类型,赋值将失败,因为 ExpressibleByArrayLiteral
需要关联的 Element
数组文字类型和您要分配给的实际数组匹配。
因此以下失败:
let words:[String] = [1, 2] // array literal has Element=Int, array has Element=String
这也表明Int
和String
之间没有隐式类型转换,即使Int
符合CustomStringConvertible
。
在你的例子中,你试图将一个由 Attributes
组成的数组文字分配给一个 String
的数组。这是类型不匹配。这就是它失败的原因。
如果您声明协议一致性,则以下行将起作用:
var attributesList: [CustomStringConvertible] {
return [
Attributes.eventDate,
Attributes.eventName,
Attributes.eventType,
Attributes.country
]
}
// note that we have an array of CustomStringConvertible protocol,
// each element here is still of Attributes type
// a type conforming to a protocol can be cast to an instance
// of that protocol automatically
// The above initialisation works simply because the following
// also works without any further action required
// let a:CustomStringConvertible = Attributes.country
如果您真的想要一个字符串值列表,您需要将其显式映射到一个字符串:
var attributesList1: [String] {
return [
Attributes.eventDate,
Attributes.eventName,
Attributes.eventType,
Attributes.country
].map { [=14=].description }
}
var attributesList2: [String] {
return [
Attributes.eventDate.description,
Attributes.eventName.description,
Attributes.eventType.description,
Attributes.country.description
]
}