介绍:
本文将记录一些特殊语法的使用方法,以及如何利用这些特殊语法给编程带来的方便,第一部分为语法记录,第二部分为编程技巧
一、语法记录
1.1 集合index相关
全新的集合用collection.index标识集合中元素位置。Array.indices 为数组中所有index的集合
let str2 = "12345678"
// collections.count
str2.count // 8
// 获取集合中元素位置
str2[str2.indices.first!] // "1"
[82, 58, 76, 49, 88, 90].indices // 0..<6
for a in str2.indices{
print(a.encodedOffset) // 0,1,2,3,4,5,6,7
}
String分割一般用 ..<
例:string.startIndex..<string.endInde
var str = "Hello, playground"
let range = str.index(str.startIndex, offsetBy: 0)..<str.index(str.startIndex, offsetBy: 5)
str[range] // "Hello"
获取字符串内容字符串长度不确定,获取长度大于字符串长度时,返回整串,目标长度小于字符串长度返回截取的子串内容
var length = 10
var contentRange:Range<String.Index>
if let content = str.index(str.startIndex, offsetBy: length, limitedBy: str.endIndex) {
contentRange = str.index(str.startIndex, offsetBy: 0)..<str.index(content, offsetBy: 0)
} else{
contentRange = str.index(str.startIndex, offsetBy: 0)..<str.index(str.endIndex, offsetBy: 0)
}
str[contentRange] // "Hello, pla"
let a = str[str.startIndex..<str.index(after: str.startIndex)] //"H"
1.2 @autoclosure(自动闭包)
自动闭包不接受任何参数,延迟求值,只有在被调用时才会返回被包装在其中的表达式的值。
在我们调用函数A获取函数结果作为参数传递给另一个函数B时,无论这个结果在函数B中是否使用,函数A都会被执行,如下第二次调用goodAfternoon(afternoon: false, who: getName())
方法后并没有使用getName的值但是函数getName
还是执行了
func getName() -> String{
print(#function)
return "DKJone"
}
func goodAfternoon(afternoon:Bool ,who:String){
if afternoon {
print("Good afternoon, \(who)")
}
}
print("------goodAfternoon(afternoon: true, who: getName())-------")
goodAfternoon(afternoon: true, who: getName())
print("------goodAfternoon(afternoon: false, who: getName())-------")
goodAfternoon(afternoon: false, who: getName())
/*log:
------goodAfternoon(afternoon: true, who: getName())-------
getName()
Good afternoon, DKJone
------goodAfternoon(afternoon: false, who: getName())-------
getName()
*/
当我们在第二个参数添加 @autoclosure
关键字后,第二个参数中的代码会在函数执行时自动生成一个闭包,只有闭包真正执行时第二个参数种类代码才会调用所以下面的goodMooning(morning: false, who: getName())
并没有调用getName
方法
//@autoclosure
func goodMooning(morning:Bool ,who:@autoclosure() -> String){
if morning {
print("Good morning, \(who())")
}
}
print("------goodMooning(morning: true, who: getName())-------")
goodMooning(morning: true, who: getName())
print("------goodMooning(morning: false, who: getName())-------")
goodMooning(morning: false, who: getName())
/* log:
------goodMooning(morning: true, who: getName())-------
getName()
Good morning, DKJone
------goodMooning(morning: false, who: getName())-------
*/
1.3 sequence(first: next: )
根据next里的闭包来生成下一个元素,和reduce完全相反。特别的是这个函数返回的是一个 UnfoldSequence
,即里面的值是lazy
的,只要在访问时才生成,这也可能是一个无限的队列。
for x in sequence(first: 0.1, next: { $0 * 2 }).prefix(while: { $0 < 4 }) {
// 0.1, 0.2, 0.4, 0.8, ...
}
似乎特别适合用来寻祖,当next闭包返回的是nil时队列就终止了:
for view in sequence(first: someView, next: { $0.superview }) {
// someView, someView.superview, someView.superview.superview, ...
}
二、编码的艺术
2.1 数组中的每个元素乘以2
(1...7).map{$0 * 2}
2.2 数组中的元素求和/排序
在swift中+-*/><=
都是一个函数/闭包
(1...10).reduce(0, +) // 55
(1...10).sorted(by: > ) // [10,9,8,7,6, 5,4,3,2,1]
2.3 验证在字符串中是否存在指定单词
let words = ["Swift","iOS","cocoa","OSX","tvOS"]
let tweet = "This is an example tweet larking about Swift"
let valid = !words.filter({tweet.contains($0)}).isEmpty // false
//或者
tweet.split(separator: " ")
.lazy
.map(String.init)
.contains(where: Set(words).contains)
2.4 一行代码输出生日歌
(1...4).forEach{print("Happy Birthday " + (($0 == 3) ? "dear Alice":"to You"))}
/*log:
Happy Birthday to You
Happy Birthday to You
Happy Birthday dear uraimo
Happy Birthday to You
*/
2.5 在数组中查找最小(或最大)值
//Find the minimum of an array of Ints
[10,-22,753,55,137,-1,-279,1034,77].sorted().first
[10,-22,753,55,137,-1,-279,1034,77].reduce(Int.max, min)
[10,-22,753,55,137,-1,-279,1034,77].min()
//Find the maximum of an array of Ints
[10,-22,753,55,137,-1,-279,1034,77].sorted().last
[10,-22,753,55,137,-1,-279,1034,77].reduce(Int.min, max)
[10,-22,753,55,137,-1,-279,1034,77].max()
2.6.过滤数组中的数字 *partition 会根据条件把集合里的元素重新排序,符合条件的元素移动到最后,返回一个两个部分分界元素的索引.
extension Sequence{
//typealias Element = Self.Iterator.Element
func partitionBy(fu: (Element)->Bool) -> ([Element],[Element]){
var first = [Element]()
var second = [Element]()
for el in self {
if fu(el) {
first.append(el)
}else{
second.append(el)
}
}
return (first,second)
}
}
let part = [82, 58, 76, 49, 88, 90].partitionBy{$0 < 60}
part // ([58, 49], [82, 76, 88, 90])
//简写一
extension Sequence{
func anotherPartitionBy(fu: (Self.Iterator.Element)->Bool)->([Self.Iterator.Element],[Self.Iterator.Element]){
return (self.filter(fu),self.filter({!fu($0)}))
}
}
let part2 = [82, 58, 76, 49, 88, 90].anotherPartitionBy{$0 < 60}
part2 // ([58, 49], [82, 76, 88, 90])
//实际应用版
var part3 = [82, 58, 76, 49, 88, 90].reduce( ([],[]), {
(a:([Int],[Int]),n:Int) -> ([Int],[Int]) in
(n<60) ? (a.0+[n],a.1) : (a.0,a.1+[n])
})
part3 // ([58, 49], [82, 76, 88, 90])
2.7 通过解构元组交换
var a=1,b=2
(a, b) = (b, a)
"a=\(a),b=\(b)" // "a=2,b=1"
2.8 正则表达式
extension String{
/// 移除小数点后结尾多余0和小数点
public var removeEndZero:String{
return replacingOccurrences(of: "[.]?[0]*$", with: "", options: [.regularExpression,.caseInsensitive])
}
/// 移除电话号码开头的 +086、086、86、+86
public var remove086Phone:String{
return replacingOccurrences(of: "^[+]?[0]?86", with: "", options: [.regularExpression,.caseInsensitive])
}
}
2.9.限制输入数字字符
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
if text == "\n"{
textView.resignFirstResponder()
return false
}
return NSPredicate(format: "SELF MATCHES %@", argumentArray: ["[\\d]?[\\cx]?"]).evaluate(with: text)
}
2.10 读取一个文件
和其他语言不同,Swift 不能使用内建的函数读取文件,并把每一行存放到数组中。不过我们可以结合 split
和 map
方法写一段简短的代码,这样就无需使用 for 循环:
let path = Bundle.main.path(forResource: "test", ofType: "txt")
let lines = try? String(contentsOfFile: path!).split{$0 == "\n"}.map(String.init)
if let lines=lines {
lines[0] // aaaaa
lines[1] // bbbbb
lines[2] // ccccc
lines[3] // ddddd
}