我只是想知道是否有更可读/更简洁的方式来编写以下内容:
let rankMap: Dictionary<Int,String> = [1:"Ace", 11:"Jack", 12:"Queen", 13:"King"]
func getCardImage(suit: String, rank: Int) -> NSImage {
var imgRank: String
if rankMap[rank] == nil {
imgRank = rank.description
} else {
imgRank = (rankMap[rank]! as NSString).substringToIndex(1)
}
let imgSuit = (suit as NSString).substringToIndex(1)
//let imgRank: String = rankMap[rank] ?? rank.description
return NSImage(named: imgRank + imgSuit)
}
特别是,我对检查rankMap的部分和nil感兴趣。无论从阵列返回什么,除了第一个被切断之外,每个角色都需要。我不能写这样的东西:
let imgRank: String = (rankMap[rank] as NSString).substringToIndex(1) ?? rank.description
..由于nil合并的语义。除了做“if nil”检查的“艰难方式”之外,还有什么我可以做的吗?
答案 0 :(得分:2)
我删除了NSImage
部分,只是因为它更容易作为文件名进行测试,但这应该表现得相似。
func cardImage(suit: String, rank: Int) -> String {
let imgRankFull = rankMap[rank] ?? rank.description
let imgRank = first(imgRankFull) ?? " "
let imgSuit = first(suit) ?? " "
return imgRank + imgSuit
}
这显示了如何使用??
,但它仍然有很多小问题IMO。我建议您使用枚举替换suit
和rank
。目前的方案有很多方法可以导致错误,而且你没有做任何好的错误检查。我已经躲过了回归&#34; &#34;,但实际上这些应该是fatalError
或可选项,或Result
(带有值或错误的对象)。
答案 1 :(得分:0)
您不需要substringToIndex
来获取Swift字符串的第一个字符。 String
是CollectionType
,标准库中的此通用函数适用于该文件:
func first<C : CollectionType>(x: C) -> C.Generator.Element?
所以你可以从尝试这样的事情开始:
let imgRank = first(rankMap[rank]) ?? rank.description // error
这不起作用,原因有两个:
String.Generator.Element
是Character
,而非String
,因此,如果您要将其放在??
表达式中,则为{{1}的右操作数1}}也需要是??
。您可以从Character
(Character
)构建String
,但如果该字符串中包含多个字符,则会崩溃。Character(rank.description)
是可选的,因此您无法将其直接传递给rankMap[rank]
。但是如果你试图立即强行解开它(使用first
,你会在查找不在字典中的东西时崩溃。您可以尝试将first(rankMap[rank]!)
置于??
调用内,同时解决这些问题,但您可能需要一个两个字符的字符串作为等级10。
如果我们可以将first
视为String
,而Array
提供var first
来获取其第一个元素,那就太好了。 (对于返回first
的字符串,有一个String
版本。)然后我们可以利用可选链接将整个表达式放在??
的左侧,然后写:
let imgRank = rankMap[rank]?.first ?? rank.description
好吧,让我们把它写在扩展名中!
extension String {
var first : String? {
// we're overloading the name of the global first() function,
// so access it with its module name
switch Swift.first(self) {
case let .Some(char):
return String(char)
case .None:
return nil
}
}
}
现在你可以很简洁:
let imgRank = rankMap[rank]?.first ?? String(rank)
(注意我也将rank.description
更改为String(rank)
。明确表示好 - description
为您提供值的字符串表示&# 39; s适合在调试器中打印; String()
将值转换为字符串。前者不能保证始终与后者匹配,因此如果您真正想要的话,请使用后者。)< / p>
无论如何,@ RobNapier的建议表明:你最好不要使用枚举。这样可以减少关于选项和无效查找的不确定性。但是看看你能用标准库做些什么总是很有用的。