我试图为[String]
编写扩展方法。
您似乎无法直接延长[String]
("类型'元素'约束到非协议类型'字符串'"虽然我遇到了这个伎俩:
protocol StringType { }
extension String: StringType { }
但我仍然无法让Swift类型系统满意:
extension Array where Element: StringType {
// ["a","b","c","d","e"] -> "a, b, c, d, or e".
func joinWithCommas() -> String {
switch count {
case 0, 1, 2:
return joinWithSeparator(" or ")
default:
return dropLast(1).joinWithSeparator(", ") + ", or " + last!
}
}
}
joinWithSeparator
来电是#34;不明确的"。我已经尝试了我能想到的一切,比如使用(self as! [String])
(以及一些类似的变体),但似乎没有任何效果。
如何让Swift编译器对此感到满意?
答案 0 :(得分:10)
编辑/更新
Swift 4 或更高版本最好将集合元素约束为StringProtocol,这也将涵盖子字符串。
extension BidirectionalCollection where Element: StringProtocol {
var joinedWithCommas: String {
guard let last = last else { return "" }
return count > 2 ? dropLast().joined(separator: ", ") + ", or " + last : joined(separator: " or ")
}
}
如果所有元素都只是字符,我们可以简单地扩展StringProtocol:
extension StringProtocol {
func joined(with separator: String = ",", conector: String = "") -> String {
guard let last = last else { return "" }
if count > 2 {
return dropLast().map(String.init).joined(separator: separator + " ") + separator + " " + conector + " " + String(last)
}
return map(String.init).joined(separator: " " + conector + " ")
}
}
let elements = "abc"
let elementsJoined = elements.joined() // "a, b, c"
let elementsSeparated = elements.joined(conector: "or") // "a, b, or c"
let elementsConected = elements.joined(conector: "and") // "a, b, and c"
原始答案
在 Swift 3.1 (Xcode 8.3.2)中,您可以简单地将Array约束元素类型扩展为String
extension Array where Element == String {
var joinedWithCommas: String {
guard let last = last else { return "" }
return count > 2 ? dropLast().joined(separator: ", ") + ", or " + last : joined(separator: " or ")
}
}
["a","b","c"].joinedWithCommas // "a, b, or c"
答案 1 :(得分:6)
您可以按照joinWithSeparator
的声明(Cmd点击它),发现它被定义为协议SequenceType
的扩展,而不是类型Array
。
// swift 2:
extension SequenceType where Generator.Element == String {
public func joinWithSeparator(separator: String) -> String
}
(注意:在Xcode 8 / Swift 3中如果您点击join(separator:)
,即使still implemented inside Sequence
,您也会登陆Array
,但是这不会使下面的想法失效)
我们可以对你的函数做同样的事情,我们扩展了Array采用的协议而不是Array本身:
// swift 2:
extension CollectionType where
Generator.Element == String,
SubSequence.Generator.Element == String,
Index: BidirectionalIndexType
{
func joinWithCommas() -> String {
switch count {
case 0, 1, 2:
return joinWithSeparator(" or ")
default:
return dropLast(1).joinWithSeparator(", ") + ", or " + last!
}
}
}
// swift 3:
extension BidirectionalCollection where
Iterator.Element == String,
SubSequence.Iterator.Element == String
{
func joinWithCommas() -> String {
switch count {
case 0, 1, 2:
return joined(separator: " or ")
default:
return dropLast().joined(separator: ", ") + ", or " + last!
}
}
}
注意:
CollectionType
以便能够使用count
Generator.Element == String
使用joinWithSeparator
SubSequence.Generator.Element == String
以确保dropLast(1)
可以使用joinWithSeparator
。 dropLast(1)
会返回关联的类型SubSequence
。Index: BidirectionalIndexType
使用last
。