Swift傻傻分不清楚系列(九)閉包

本頁包含內容:

  • 閉包表達式(Closure Expressions)
  • 尾隨閉包(Trailing Closures)
  • 值捕獲(Capturing Values)
  • 閉包是引用類型(Closures Are Reference Types)
  • 非逃逸閉包(Nonescaping Closures)
  • 自動閉包(Autoclosures)

閉包是自包含的函數代碼塊,可以在代碼中被傳遞和使用。Swift 中的閉包與 C 和 Objective-C 中的代碼塊(blocks)以及其他一些編程語言中的匿名函數比較相似。

閉包可以捕獲和存儲其所在上下文中任意常量和變量的引用。這就是所謂的閉合并包裹著這些常量和變量,俗稱閉包。Swift 會為您管理在捕獲過程中涉及到的所有內存操作。

在函數章節中介紹的全局和嵌套函數實際上也是特殊的閉包,閉包采取如下三種形式之一:

  • 全局函數是一個有名字但不會捕獲任何值的閉包
  • 嵌套函數是一個有名字并可以捕獲其封閉函數域內值的閉包
  • 閉包表達式是一個利用輕量級語法所寫的可以捕獲其上下文中變量或常量值的匿名閉包

Swift 的閉包表達式擁有簡潔的風格,并鼓勵在常見場景中進行語法優化,主要優化如下:

  • 利用上下文推斷參數和返回值類型
  • 隱式返回單表達式閉包,即單表達式閉包可以省略return關鍵字
  • 參數名稱縮寫
  • 尾隨(Trailing)閉包語法

閉包表達式(Closure Expressions)

嵌套函數是一個在較復雜函數中方便進行命名和定義自包含代碼模塊的方式。當然,有時候撰寫小巧的沒有完整定義和命名的類函數結構也是很有用處的,尤其是在您處理一些函數并需要將另外一些函數作為該函數的參數時。

閉包表達式是一種利用簡潔語法構建內聯閉包的方式。閉包表達式提供了一些語法優化,使得撰寫閉包變得簡單明了。下面閉包表達式的例子通過使用幾次迭代展示了sort(_:)方法定義和語法優化的方式。每一次迭代都用更簡潔的方式描述了相同的功能。

sort 方法(The Sort Method)

Swift 標準庫提供了名為sort的方法,會根據您提供的用于排序的閉包函數將已知類型數組中的值進行排序。一旦排序完成,sort(_:)方法會返回一個與原數組大小相同,包含同類型元素且元素已正確排序的新數組。原數組不會被sort(_:)方法修改。

下面的閉包表達式示例使用sort(_:)方法對一個String類型的數組進行字母逆序排序.以下是初始數組值:

let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]

sort(_:)方法接受一個閉包,該閉包函數需要傳入與數組元素類型相同的兩個值,并返回一個布爾類型值來表明當排序結束后傳入的第一個參數排在第二個參數前面還是后面。如果第一個參數值出現在第二個參數值前面,排序閉包函數需要返回true,反之返回false

該例子對一個String類型的數組進行排序,因此排序閉包函數類型需為(String, String) -> Bool

提供排序閉包函數的一種方式是撰寫一個符合其類型要求的普通函數,并將其作為sort(_:)方法的參數傳入:

func backwards(s1: String, s2: String) -> Bool {return s1 > s2
}
var reversed = names.sort(backwards)
// reversed 為 ["Ewa", "Daniella", "Chris", "Barry", "Alex"]

如果第一個字符串(s1)大于第二個字符串(s2),backwards(_:_:)函數返回true,表示在新的數組中s1應該出現在s2前。對于字符串中的字符來說,“大于”表示“按照字母順序較晚出現”。這意味著字母"B"大于字母"A",字符串"Tom"大于字符串"Tim"。該閉包將進行字母逆序排序,"Barry"將會排在"Alex"之前。

然而,這是一個相當冗長的方式,本質上只是寫了一個單表達式函數 (a > b)。在下面的例子中,利用閉包表達式語法可以更好地構造一個內聯排序閉包。

閉包表達式語法(Closure Expression Syntax)

閉包表達式語法有如下一般形式:

{ (parameters) -> returnType instatements
}

閉包表達式語法可以使用常量、變量和inout類型作為參數,不能提供默認值。也可以在參數列表的最后使用可變參數。元組也可以作為參數和返回值。

下面的例子展示了之前backwards(_:_:)函數對應的閉包表達式版本的代碼:

reversed = names.sort({ (s1: String, s2: String) -> Bool inreturn s1 > s2
})

需要注意的是內聯閉包參數和返回值類型聲明與backwards(_:_:)函數類型聲明相同。在這兩種方式中,都寫成了(s1: String, s2: String) -> Bool。然而在內聯閉包表達式中,函數和返回值類型都寫在大括號內,而不是大括號外。

閉包的函數體部分由關鍵字in引入。該關鍵字表示閉包的參數和返回值類型定義已經完成,閉包函數體即將開始。

由于這個閉包的函數體部分如此短,以至于可以將其改寫成一行代碼:

reversed = names.sort( { (s1: String, s2: String) -> Bool in return s1 > s2 } )

該例中sort(_:)方法的整體調用保持不變,一對圓括號仍然包裹住了方法的整個參數。然而,參數現在變成了內聯閉包。

根據上下文推斷類型(Inferring Type From Context)

因為排序閉包函數是作為sort(_:)方法的參數傳入的,Swift 可以推斷其參數和返回值的類型。sort(_:)方法被一個字符串數組調用,因此其參數必須是(String, String) -> Bool類型的函數。這意味著(String, String)Bool類型并不需要作為閉包表達式定義的一部分。因為所有的類型都可以被正確推斷,返回箭頭(->)和圍繞在參數周圍的括號也可以被省略:

reversed = names.sort( { s1, s2 in return s1 > s2 } )

實際上任何情況下,通過內聯閉包表達式構造的閉包作為參數傳遞給函數或方法時,都可以推斷出閉包的參數和返回值類型。 這意味著閉包作為函數或者方法的參數時,您幾乎不需要利用完整格式構造內聯閉包。

盡管如此,您仍然可以明確寫出有著完整格式的閉包。如果完整格式的閉包能夠提高代碼的可讀性,則可以采用完整格式的閉包。而在sort(_:)方法這個例子里,閉包的目的就是排序。由于這個閉包是為了處理字符串數組的排序,因此讀者能夠推測出這個閉包是用于字符串處理的。

單表達式閉包隱式返回(Implicit Return From Single-Expression Clossures)

單行表達式閉包可以通過省略return關鍵字來隱式返回單行表達式的結果,如上版本的例子可以改寫為:

reversed = names.sort( { s1, s2 in s1 > s2 } )

在這個例子中,sort(_:)方法的參數類型明確了閉包必須返回一個Bool類型值。因為閉包函數體只包含了一個單一表達式(s1 > s2),該表達式返回Bool類型值,因此這里沒有歧義,return關鍵字可以省略。

參數名稱縮寫(Shorthand Argument Names)

Swift 自動為內聯閉包提供了參數名稱縮寫功能,您可以直接通過$0$1$2來順序調用閉包的參數,以此類推。

如果您在閉包表達式中使用參數名稱縮寫,您可以在閉包參數列表中省略對其的定義,并且對應參數名稱縮寫的類型會通過函數類型進行推斷。in關鍵字也同樣可以被省略,因為此時閉包表達式完全由閉包函數體構成:

reversed = names.sort( { $0 > $1 } )

在這個例子中,$0$1表示閉包中第一個和第二個String類型的參數。

運算符函數(Operator Functions)

實際上還有一種更簡短的方式來撰寫上面例子中的閉包表達式。Swift 的String類型定義了關于大于號(>)的字符串實現,其作為一個函數接受兩個String類型的參數并返回Bool類型的值。而這正好與sort(_:)方法的參數需要的函數類型相符合。因此,您可以簡單地傳遞一個大于號,Swift 可以自動推斷出您想使用大于號的字符串函數實現:

reversed = names.sort(>)

尾隨閉包(Trailing Closures)

如果您需要將一個很長的閉包表達式作為最后一個參數傳遞給函數,可以使用尾隨閉包來增強函數的可讀性。尾隨閉包是一個書寫在函數括號之后的閉包表達式,函數支持將其作為最后一個參數調用:

func someFunctionThatTakesAClosure(closure: () -> Void) {// 函數體部分
}// 以下是不使用尾隨閉包進行函數調用
someFunctionThatTakesAClosure({// 閉包主體部分
})// 以下是使用尾隨閉包進行函數調用
someFunctionThatTakesAClosure() {// 閉包主體部分
}

在閉包表達式語法一節中作為sort(_:)方法參數的字符串排序閉包可以改寫為:

reversed = names.sort() { $0 > $1 }

如果函數只需要閉包表達式一個參數,當您使用尾隨閉包時,您甚至可以把()省略掉:

reversed = names.sort { $0 > $1 }

當閉包非常長以至于不能在一行中進行書寫時,尾隨閉包變得非常有用。舉例來說,Swift 的Array類型有一個map(_:)方法,其獲取一個閉包表達式作為其唯一參數。該閉包函數會為數組中的每一個元素調用一次,并返回該元素所映射的值。具體的映射方式和返回值類型由閉包來指定。

當提供給數組的閉包應用于每個數組元素后,map(_:)方法將返回一個新的數組,數組中包含了與原數組中的元素一一對應的映射后的值。

下例介紹了如何在map(_:)方法中使用尾隨閉包將Int類型數組[16, 58, 510]轉換為包含對應String類型的值的數組["OneSix", "FiveEight", "FiveOneZero"]

let digitNames = [0: "Zero", 1: "One", 2: "Two",   3: "Three", 4: "Four",5: "Five", 6: "Six", 7: "Seven", 8: "Eight", 9: "Nine"
]
let numbers = [16, 58, 510]

如上代碼創建了一個數字位和它們英文版本名字相映射的字典。同時還定義了一個準備轉換為字符串數組的整型數組。

您現在可以通過傳遞一個尾隨閉包給numbersmap(_:)方法來創建對應的字符串版本數組:

let strings = numbers.map {(number) -> String invar number = numbervar output = ""while number > 0 {output = digitNames[number % 10]! + outputnumber /= 10}return output
}
// strings 常量被推斷為字符串類型數組,即 [String]
// 其值為 ["OneSix", "FiveEight", "FiveOneZero"]

map(_:)為數組中每一個元素調用了閉包表達式。您不需要指定閉包的輸入參數number的類型,因為可以通過要映射的數組類型進行推斷。

在該例中,局部變量number的值由閉包中的number參數獲得,因此可以在閉包函數體內對其進行修改,(閉包或者函數的參數總是常量),閉包表達式指定了返回類型為String,以表明存儲映射值的新數組類型為String

閉包表達式在每次被調用的時候創建了一個叫做output的字符串并返回。其使用求余運算符(number % 10)計算最后一位數字并利用digitNames字典獲取所映射的字符串。

注意
字典digitNames下標后跟著一個嘆號(!),因為字典下標返回一個可選值(optional value),表明該鍵不存在時會查找失敗。在上例中,由于可以確定number % 10總是digitNames字典的有效下標,因此嘆號可以用于強制解包 (force-unwrap) 存儲在下標的可選類型的返回值中的String類型的值。

digitNames字典中獲取的字符串被添加到output的前部,逆序建立了一個字符串版本的數字。(在表達式number % 10中,如果number16,則返回658返回8510返回0。)

number變量之后除以10。因為其是整數,在計算過程中未除盡部分被忽略。因此16變成了158變成了5510變成了51

整個過程重復進行,直到number /= 100,這時閉包會將字符串output返回,而map(_:)方法則會將字符串添加到所映射的數組中。

在上面的例子中,通過尾隨閉包語法,優雅地在函數后封裝了閉包的具體功能,而不再需要將整個閉包包裹在map(_:)方法的括號內。

捕獲值(Capturing Values)

閉包可以在其被定義的上下文中捕獲常量或變量。即使定義這些常量和變量的原作用域已經不存在,閉包仍然可以在閉包函數體內引用和修改這些值。

Swift 中,可以捕獲值的閉包的最簡單形式是嵌套函數,也就是定義在其他函數的函數體內的函數。嵌套函數可以捕獲其外部函數所有的參數以及定義的常量和變量。

舉個例子,這有一個叫做makeIncrementor的函數,其包含了一個叫做incrementor的嵌套函數。嵌套函數incrementor()從上下文中捕獲了兩個值,runningTotalamount。捕獲這些值之后,makeIncrementorincrementor作為閉包返回。每次調用incrementor時,其會以amount作為增量增加runningTotal的值。

func makeIncrementor(forIncrement amount: Int) -> () -> Int {var runningTotal = 0func incrementor() -> Int {runningTotal += amountreturn runningTotal}return incrementor
}

makeIncrementor返回類型為() -> Int。這意味著其返回的是一個函數,而不是一個簡單類型的值。該函數在每次調用時不接受參數,只返回一個Int類型的值。

makeIncrementer(forIncrement:)函數定義了一個初始值為0的整型變量runningTotal,用來存儲當前跑步總數。該值通過incrementor返回。

makeIncrementer(forIncrement:)有一個Int類型的參數,其外部參數名為forIncrement,內部參數名為amount,該參數表示每次incrementor被調用時runningTotal將要增加的量。

嵌套函數incrementor用來執行實際的增加操作。該函數簡單地使runningTotal增加amount,并將其返回。

如果我們單獨看這個函數,會發現看上去不同尋常:

func incrementor() -> Int {runningTotal += amountreturn runningTotal
}

incrementer()函數并沒有任何參數,但是在函數體內訪問了runningTotalamount變量。這是因為它從外圍函數捕獲了runningTotalamount變量的引用。捕獲引用保證了runningTotalamount變量在調用完makeIncrementer后不會消失,并且保證了在下一次執行incrementer函數時,runningTotal依舊存在。

注意
為了優化,如果一個值是不可變的,Swift 可能會改為捕獲并保存一份對值的拷貝。
Swift 也會負責被捕獲變量的所有內存管理工作,包括釋放不再需要的變量。

下面是一個使用makeIncrementor的例子:

let incrementByTen = makeIncrementor(forIncrement: 10)

該例子定義了一個叫做incrementByTen的常量,該常量指向一個每次調用會將runningTotal變量增加10incrementor函數。調用這個函數多次可以得到以下結果:

incrementByTen()
// 返回的值為10
incrementByTen()
// 返回的值為20
incrementByTen()
// 返回的值為30

如果您創建了另一個incrementor,它會有屬于它自己的一個全新、獨立的runningTotal變量的引用:

let incrementBySeven = makeIncrementor(forIncrement: 7)
incrementBySeven()
// 返回的值為7

再次調用原來的incrementByTen會在原來的變量runningTotal上繼續增加值,該變量和incrementBySeven中捕獲的變量沒有任何聯系:

incrementByTen()
// 返回的值為40

注意
如果您將閉包賦值給一個類實例的屬性,并且該閉包通過訪問該實例或其成員而捕獲了該實例,您將創建一個在閉包和該實例間的循環強引用。Swift 使用捕獲列表來打破這種循環強引用。

閉包是引用類型(Closures Are Reference Types)

上面的例子中,incrementBySevenincrementByTen是常量,但是這些常量指向的閉包仍然可以增加其捕獲的變量的值。這是因為函數和閉包都是引用類型

無論您將函數或閉包賦值給一個常量還是變量,您實際上都是將常量或變量的值設置為對應函數或閉包的引用。上面的例子中,指向閉包的引用incrementByTen是一個常量,而并非閉包內容本身。

這也意味著如果您將閉包賦值給了兩個不同的常量或變量,兩個值都會指向同一個閉包:

let alsoIncrementByTen = incrementByTen
alsoIncrementByTen()
// 返回的值為50

非逃逸閉包(Nonescaping Closures)

當一個閉包作為參數傳到一個函數中,但是這個閉包在函數返回之后才被執行,我們稱該閉包從函數中逃逸。當你定義接受閉包作為參數的函數時,你可以在參數名之前標注@noescape,用來指明這個閉包是不允許“逃逸”出這個函數的。將閉包標注@noescape能使編譯器知道這個閉包的生命周期(譯者注:閉包只能在函數體中被執行,不能脫離函數體執行,所以編譯器明確知道運行時的上下文),從而可以進行一些比較激進的優化。

func someFunctionWithNoescapeClosure(@noescape closure: () -> Void) {closure()
}

舉個例子,sort(_:)方法接受一個用來進行元素比較的閉包作為參數。這個參數被標注了@noescape,因為它確保自己在排序結束之后就沒用了。

一種能使閉包“逃逸”出函數的方法是,將這個閉包保存在一個函數外部定義的變量中。舉個例子,很多啟動異步操作的函數接受一個閉包參數作為 completion handler。這類函數會在異步操作開始之后立刻返回,但是閉包直到異步操作結束后才會被調用。在這種情況下,閉包需要“逃逸”出函數,因為閉包需要在函數返回之后被調用。例如:

var completionHandlers: [() -> Void] = []
func someFunctionWithEscapingClosure(completionHandler: () -> Void) {completionHandlers.append(completionHandler)
}

someFunctionWithEscapingClosure(_:)函數接受一個閉包作為參數,該閉包被添加到一個函數外定義的數組中。如果你試圖將這個參數標注為@noescape,你將會獲得一個編譯錯誤。

將閉包標注為@noescape使你能在閉包中隱式地引用self

class SomeClass {var x = 10func doSomething() {someFunctionWithEscapingClosure { self.x = 100 }someFunctionWithNoescapeClosure { x = 200 }}
}let instance = SomeClass()
instance.doSomething()
print(instance.x)
// prints "200"completionHandlers.first?()
print(instance.x)
// prints "100"

自動閉包(Autoclosures)

自動閉包是一種自動創建的閉包,用于包裝傳遞給函數作為參數的表達式。這種閉包不接受任何參數,當它被調用的時候,會返回被包裝在其中的表達式的值。這種便利語法讓你能夠用一個普通的表達式來代替顯式的閉包,從而省略閉包的花括號。

我們經常會調用一個接受閉包作為參數的函數,但是很少實現那樣的函數。舉個例子來說,assert(condition:message:file:line:)函數接受閉包作為它的condition參數和message參數;它的condition參數僅會在 debug 模式下被求值,它的message參數僅當condition參數為false時被計算求值。

自動閉包讓你能夠延遲求值,因為代碼段不會被執行直到你調用這個閉包。延遲求值對于那些有副作用(Side Effect)和代價昂貴的代碼來說是很有益處的,因為你能控制代碼什么時候執行。下面的代碼展示了閉包如何延時求值。

var customersInLine = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
print(customersInLine.count)
// prints "5"let customerProvider = { customersInLine.removeAtIndex(0) }
print(customersInLine.count)
// prints "5"print("Now serving \(customerProvider())!")
// prints "Now serving Chris!"
print(customersInLine.count)
// prints "4"

盡管在閉包的代碼中,customersInLine的第一個元素被移除了,不過在閉包被調用之前,這個元素是不會被移除的。如果這個閉包永遠不被調用,那么在閉包里面的表達式將永遠不會執行,那意味著列表中的元素永遠不會被移除。請注意,customerProvider的類型不是String,而是() -> String,一個沒有參數且返回值為String的函數。

將閉包作為參數傳遞給函數時,你能獲得同樣的延時求值行為。

// customersInLine is ["Alex", "Ewa", "Barry", "Daniella"]
func serveCustomer(customerProvider: () -> String) {print("Now serving \(customerProvider())!")
}
serveCustomer( { customersInLine.removeAtIndex(0) } )
// prints "Now serving Alex!"

serveCustomer(_:)接受一個返回顧客名字的顯式的閉包。下面這個版本的serveCustomer(_:)完成了相同的操作,不過它并沒有接受一個顯式的閉包,而是通過將參數標記為@autoclosure來接收一個自動閉包。現在你可以將該函數當做接受String類型參數的函數來調用。customerProvider參數將自動轉化為一個閉包,因為該參數被標記了@autoclosure特性。

// customersInLine is ["Ewa", "Barry", "Daniella"]
func serveCustomer(@autoclosure customerProvider: () -> String) {print("Now serving \(customerProvider())!")
}
serveCustomer(customersInLine.removeAtIndex(0))
// prints "Now serving Ewa!"

注意
過度使用autoclosures會讓你的代碼變得難以理解。上下文和函數名應該能夠清晰地表明求值是被延遲執行的。

@autoclosure特性暗含了@noescape特性,這個特性在非逃逸閉包一節中有描述。如果你想讓這個閉包可以“逃逸”,則應該使用@autoclosure(escaping)特性.

// customersInLine is ["Barry", "Daniella"]
var customerProviders: [() -> String] = []
func collectCustomerProviders(@autoclosure(escaping) customerProvider: () -> String) {customerProviders.append(customerProvider)
}
collectCustomerProviders(customersInLine.removeAtIndex(0))
collectCustomerProviders(customersInLine.removeAtIndex(0))print("Collected \(customerProviders.count) closures.")
// prints "Collected 2 closures."
for customerProvider in customerProviders {print("Now serving \(customerProvider())!")
}
// prints "Now serving Barry!"
// prints "Now serving Daniella!"

在上面的代碼中,collectCustomerProviders(_:)函數并沒有調用傳入的customerProvider閉包,而是將閉包追加到了customerProviders數組中。這個數組定義在函數作用域范圍外,這意味著數組內的閉包將會在函數返回之后被調用。因此,customerProvider參數必須允許“逃逸”出函數作用域。


再次感謝~~~~~~~~~~~~~

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/248060.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/248060.shtml
英文地址,請注明出處:http://en.pswp.cn/news/248060.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Ajax — 新聞列表

注意&#xff1a;本項目主要利用到了template&#xff0c;模板引擎進行編寫 模板引擎代碼下載地址 <div id"news-list"><!-- 這里放數據 --></div>.news-item {display: flex;border: 1px solid #eee;width: 700px;padding: 10px;margin-bottom: …

vim下更省心地用中文

在vim下使用中文是個麻煩。除了寫代碼&#xff0c;很多時候也需要做筆記。以下介紹rime輸入法的一個功能&#xff0c;它可以減少vim下中文輸入帶來的麻煩。在***.custom.yaml下添加代碼&#xff1a; "key_binder/bindings": - { when: always, accept: ReleaseEs…

Python 常見的內置模塊

1. abs() 函數 描述 abs() 函數返回數字的絕對值 #!/usr/bin/pythonprint "abs(-45) : ", abs(-45) print "abs(100.12) : ", abs(100.12) print "abs(119L) : ", abs(119L)以上實例運行后輸出結果為&#xff1a;abs(-45) : 45 abs(100.12) : …

Ajax — 第四天

數據交換格式 XML 寫法&#xff1a; 一個文檔有且只有一個根標簽標簽必須閉合屬性值必須加引號 如果說服務器返回的數據是xml格式的 前端需要把服務器返回的xml當做document對象來處理目前無法演示&#xff0c;自己寫接口的時候&#xff0c;我們可以測試一下。 JSON 寫法…

檢測字符串包含emoji表情

有時候在開發時會遇到不希望字符串中包含emoji表情的情況&#xff0c;Google之后發現了方法&#xff0c;但是似乎iOS9之后的emoji無法過濾&#xff0c;繼續尋找方法&#xff0c;在一個NSString的擴展中發現了辦法 #import <Foundation/Foundation.h>/**Category to searc…

數據庫系統原理(第三章數據庫設計 )

一、數據庫設計概述 數據庫的生命周期 數據庫設計的目標&#xff1a; 滿足應用功能需求&#xff08;存、取、刪、改&#xff09;&#xff0c;良好的數 據庫性能&#xff08;數據的高效率存取和空間的節省 共享性、完整性、一致性、安全保密性&#xff09;數據庫設計的內容 數據…

Ajax — 第五天

Ajax-05 xhr&#xff08;level-2&#xff09;新特性 responseType屬性和response屬性 responseType: 表示預期服務器返回的數據的類型 “” &#xff0c;默認空text&#xff0c;和空一樣&#xff0c;表示服務器返回的數據是字符串格式json&#xff0c;表示服務器返回的是js…

java 根據身份證號碼獲取出生日期、性別、年齡

1.情景展示 如何根據身份證號&#xff0c;計算出出生日期、性別、年齡? 2.解決方案 從網上找的別人的&#xff0c;因為并沒有實際用到&#xff0c;所以并未對其優化&#xff01; /*** 通過身份證號碼獲取出生日期、性別、年齡* param certificateNo* return 返回的出生日期格式…

Swift傻傻分不清楚系列(十)枚舉

本頁內容包含&#xff1a; 枚舉語法&#xff08;Enumeration Syntax&#xff09;使用 Switch 語句匹配枚舉值&#xff08;Matching Enumeration Values with a Switch Statement&#xff09;關聯值&#xff08;Associated Values&#xff09;原始值&#xff08;Raw Values&…

數據庫系統原理(第四章:SQL與關系數據庫基本操作 )

一、SQL概述 sql是結構化查詢語言&#xff08;Structured Query Language&#xff0c;SQL&#xff09;是專門用來與數 據庫通信的語言&#xff0c;它可以幫助用戶操作關系數據庫。 SQL的特點&#xff1a; SQL不是某個特定數據庫供應商專有的語言&#xff1b; SQL簡單易學 &…

selenium操作瀏覽器窗口最大化和刷新

實際測試過程中經常遇到打開一個頁面并不是全屏顯示&#xff0c;但是卻希望它能夠全屏顯示或者新增一條記錄后需要刷新一下看能不能再列表中正常顯示。 于是就有了今天的關于對瀏覽器窗口的最大化和刷新頁面。需要說明的一點&#xff1a;所有和python相關的記錄都是基于3.6版本…

Git安裝步驟+Mac終端配置

Git安裝步驟 其實可以直接略過。因為安裝的時候&#xff0c;一路 next 即可。 注意&#xff0c;安裝路徑中不能出現中文。安裝完成后&#xff0c;不得更改安裝路徑。 檢查Git是否安裝成功 在任何文件夾&#xff0c;空白處&#xff0c;右鍵。如果看到 “Git Bash Here”&#xf…

Swift傻傻分不清楚系列(十一)類和結構體

本頁包含內容&#xff1a; 類和結構體對比結構體和枚舉是值類型類是引用類型類和結構體的選擇字符串(String)、數組(Array)、和字典(Dictionary)類型的賦值與復制行為 類和結構體是人們構建代碼所用的一種通用且靈活的構造體。我們可以使用完全相同的語法規則來為類和結構體定義…

數據庫系統原理(第5章:數據庫編程)

一、存儲過程 概念&#xff1a;存儲過程是一組為了完成某項特定功能的SQL語句集&#xff0c; 其實質就是一段存儲在數據庫中的代碼。 它可以由聲明式的sql語句和過程式sql語句組成。 特點&#xff1a; 可增強SQL語言的功能和靈活性良好的封裝性高性能可減少網絡流量可作為一種安…

科學-中醫:儒醫

ylbtech-科學-中醫&#xff1a;儒醫"儒醫"是一種歷史悠久的社會文化現象。闡釋了"儒醫"的三重境界,即良醫、大醫、圣醫。"良醫"注重技,屬于知識論,追求的是"真";"大醫"注重德,屬于道德論,追求的是"善";"圣醫…

Ajax — 第六天

Ajax-06 GET和POST的區別 字面意思不同 GET 是獲取意思。想從服務器獲取數據&#xff0c;用GET方式的請求POST是郵遞、郵寄意思。如果提交數據到服務器&#xff0c;用POST方式 請求參數位置不同 GET 請求參數會和url拼接到一起&#xff0c;形如 api/getbooks?id2&age3PO…

iOS Tips 模擬器屏幕截圖

當我們發布app到AppStore的時候&#xff0c;在itunes connect里面&#xff0c;蘋果官方要求我們提供各種尺寸的屏幕截圖。由于受到硬件條件的限制&#xff0c;我們不可能在每個真實的物理機器上測試并截圖&#xff0c;相反如果我們能直接在模擬器上進行屏幕截圖的話&#xff0c…

數據庫系統原理(第6章:數據庫安全與保護)

一、數據庫完整性 數據庫完整性是指數據庫中數據的正確性和相容性。 完整性約束條件的作用對象 列級約束&#xff1a; 包括對列的類型、取值范圍、精度等的約束元組約束&#xff1a; 指元組中各個字段之間的相互約束表級約束&#xff1a; 指若干元組、關系之間的聯系的約束定義…

.net core WebApi 使用Swagger生成API文檔

關于 Swagger Swagger能成為最受歡迎的REST APIs文檔生成工具之一&#xff0c;有以下幾個原因&#xff1a; Swagger 可以生成一個具有互動性的API控制臺&#xff0c;開發者可以用來快速學習和嘗試API。Swagger 可以生成客戶端SDK代碼用于各種不同的平臺上的實現。Swagger 文件可…

Git — 初體驗

準備工作 版本管理軟件 作用 記錄代碼的版本實現多人協作 分類 集中式&#xff0c;典型代表 SVN分布式&#xff0c;典型代表 Git 注冊遠程倉庫賬號 遠程倉庫相當于中央服務器我們需要在github上或碼云上注冊一個賬號&#xff0c;用于創建遠程倉庫使用注冊的時候&#xff0…