将单个整数值视为Swift中的一个范围
我需要验证字符串的长度。为字符计数的允许值包括:将单个整数值视为Swift中的一个范围
- 6 - 9个字符
- 12个字符
- 15个字符
所有字符串与不同的字符计数是无效的。因此,我想创建接受一个数范围,并评估串的夫特功能:
extension String {
func evaluateLength(validCharacterCounts: Range<Int>...) -> Bool {
// Implementation
}
}
现在我可以调用该函数用于单个Int
范围:
"Live long and prosper".evaluateLength(validCharacterCounts: 6..<10)
和多个Int
范围:
"Live long and prosper".evaluateLength(validCharacterCounts: 6..<10, 15..<20)
但我不能用单一的,分离的整数值调用函数:
"Live long and prosper".evaluateLength(validCharacterCounts: 6..<10, 12, 15)
因为12
和15
被分类为Int
而不是Range<Int>
。
Swift compile error: Cannot convert value of type 'Int' to expected argument type 'Range'
有没有一种方式来对待一个整数,如斯威夫特一个Range
,像自动浇铸成Range<Int>
?
(毕竟5
相当于5..<6
,所以从数学上讲5
是一个范围为好。)
我想出了3个解决方案,但我也不都是那样令人开心的是,如果该方法接受Int
或Range<Int>
但我们在这里?
1 - 你有类型安全,而且必须使用一些变通方法:
extension String {
func evaluateLength(validCharacterCounts: [Range<Int>]? = nil) -> Bool {
if let validCharCounts = validCharacterCounts {
for validCharCount in validCharCounts {
if validCharCount.contains(characters.count) {
return true
}
}
}
return false
}
}
extension Int {
var asRange: Range<Int> {
return self..<self+1 as Range<Int>
}
}
"Hello, playground".evaluateLength(validCharacterCounts: [17.asRange, 1, 25, 1..<45]) // true
2 - 您没有类型安全:
extension String {
func evaluateLength(validCharacterCounts: [Any]? = nil) -> Bool {
if let validCharCounts = validCharacterCounts {
for validCharCount in validCharCounts {
if let range = validCharCount as? Range<Int> {
if range.contains(characters.count) {
return true
}
} else if let range = validCharCount as? CountableRange<Int> {
if range.contains(characters.count) {
return true
}
} else if let range = validCharCount as? CountableClosedRange<Int> {
if range.contains(characters.count) {
return true
}
} else if let int = validCharCount as? Int {
if int.asRange.contains(characters.count) {
return true
}
} else {
fatalError("Unexpected type: \(type(of: validCharCount))")
}
}
}
return false
}
}
extension Int {
var asRange: Range<Int> {
return self..<self+1 as Range<Int>
}
}
"Hello, playground".evaluateLength(validCharacterCounts: [12, 1, 4, 6, 14...18]) // true
3 - 迄今最好的,但仍不完美的解决方案:
extension String {
func evaluateLength(validCharacterCounts: [Int]? = nil) -> Bool {
guard let validCharCounts = validCharacterCounts else {
return false
}
return validCharCounts.contains(characters.count)
}
}
"Hello, playground".evaluateLength(validCharacterCounts: [12, 1, 4, 6] + Array(14...18)) // true
我很喜欢类型安全,所以我不太欣赏2。 3几乎是我最终实现自己,但它不能解决问题,因为你仍然需要以不同的方式处理范围和单个整数。谢谢你的想法! :) – Mischa
这是我该怎么做。而不是处理范围语义,我只是用相关的初始化工具创建一个Set扩展。
extension Set where Element == Int {
init(with elements: [Int] = [], and ranges: Range<Int>...) {
var allElements = [elements]
ranges.forEach {
allElements.append(Array($0.lowerBound..<$0.upperBound))
}
self.init(allElements.joined())
}
}
let newSet = Set(with: [1, 3, 328], and: 6..<10, 15..<20)
newSet.contains(3) //true
newSet.contains(4) //false
newSet.contains(16) //true
这允许您仅传递单个值,仅传递范围或两者。唯一的注意事项是命名的参数将它们分开。
Set
语义也意味着你可以创建静态常量,如果需要,也应该明显更快。
我一直在尝试使用Sets。但是,这种方法在两个不同整数之间引入了“单个整数范围”和“实际”间隔之间的分隔。这就是为什么我问这个问题的原因,因为它们在语义上是_both_范围,所以我想以相同的方式对待它们。 – Mischa
'evaluateLength(validCharacterCounts:5,7,10 ... 20,25)'比'evaluateLength(validCharacterCounts:5,7,25,validCharacterCountRanges:10 ... 20)'更直观。 – Mischa
@Mischa我同意这样做很好,我试图找到一种协议的方式,但它可能不是类型安全目前可能的。 (这可能会在Swift 4中改变) – PeejWeej
另一种方法是传递一个'IndexSet'类型的参数。 –
你的意思是像'evaluateLength(validCharacterCounts:IndexSet(6 .. Mischa