在這個(gè)教程中,大家最好能夠?qū)τ?Linux 操作系統(tǒng)有使用經(jīng)驗(yàn)。有簡(jiǎn)單的 Shell 命令使用經(jīng)驗(yàn)。我們遇到的所有的操作基本都是通過(guò)命令行來(lái)進(jìn)行的。雖然我也很喜歡圖形界面操作,這也是趨勢(shì),但是 C 語(yǔ)言目前主要的應(yīng)用場(chǎng)景都是在 Linux 下,所以大家最好學(xué)習(xí)一下相關(guān)的知識(shí)。
Markdown 本身沒(méi)有為圖片增加特殊的樣式,如果我們需要特殊定義,可以通過(guò) 手動(dòng)修改全局樣式 <style> 實(shí)現(xiàn)。實(shí)例 3:圓形圖片。#### 使圖片圓角<style> img { border-radius: 50% !important; border: 30px solid #eee; }</style>其渲染結(jié)果如下:圖片來(lái)源于網(wǎng)絡(luò),版權(quán)歸原作者所有
從原集合的最后一項(xiàng)開(kāi)始倒序取集合的元素,取 n 個(gè)元素,最后返回取出這些元素的集合。源碼定義public fun <T> List<T>.takeLast(n: Int): List<T> { require(n >= 0) { "Requested element count $n is less than zero." } if (n == 0) return emptyList()//n為0表示取0個(gè)元素的集合,返回空集合 val size = size if (n >= size) return toList()//如果取的元素集合大小大于size直接返回整個(gè)集合 if (n == 1) return listOf(last())//從最后一項(xiàng)開(kāi)始取1個(gè)元素,自然就是返回last() val list = ArrayList<T>(n)//創(chuàng)建一個(gè)n大小的可變集合 if (this is RandomAccess) {//RandomAccess是一個(gè)集合標(biāo)記接口,如果集合類(lèi)是RandomAccess的實(shí)現(xiàn),則盡量用index下標(biāo) 來(lái)遍歷而不要用Iterator迭代器來(lái)遍歷,在效率上要差一些。反過(guò)來(lái),如果List是Sequence List,則最好用迭代器來(lái)進(jìn)行迭代。 for (index in size - n until size)//采用下邊遍歷 list.add(this[index]) } else { for (item in listIterator(size - n))//采用迭代器遍歷 list.add(item) } return list}原理圖解使用場(chǎng)景適用于倒序從最后一項(xiàng)開(kāi)始取集合中子集合fun main(args: Array<String>) { val strList = listOf("java", "javaScript", "kotlin", "C", "C++", "javaFx", "python","Go", "Swift", "Scala") strList.takeLast(2).forEach { print("$it ") }}
make 工具是用來(lái)構(gòu)建 C 程序而發(fā)明的。特別是當(dāng)需要依賴(lài)大量的庫(kù)文件(尤其是非標(biāo)準(zhǔn)庫(kù)文件),和需要設(shè)置一些特殊的系統(tǒng)變量環(huán)境等內(nèi)容的時(shí)候。通常情況下, make 工具都會(huì)用在比較大的項(xiàng)目中。但是如果在規(guī)模不大的程序中使用會(huì)更簡(jiǎn)單,同時(shí)會(huì)讓你的程序構(gòu)建變得也更輕松。要使用 make 工具就需要寫(xiě)一個(gè) makefile,通常情況下這個(gè)文件名就是叫 makefile。當(dāng)然你可以用別的名字替代。不過(guò)這個(gè)時(shí)候你就要在執(zhí)行 make 命令的時(shí)候指定你所要執(zhí)行的 makefile 文件名。如果寫(xiě)成 makefile 這個(gè)名字, make 程序會(huì)直接在當(dāng)前所在的文件夾中尋找這個(gè)文件,就不用指定文件名字了。所以,建議大家就用 makefile 這個(gè)英文單詞的名字。make 工具其實(shí)不僅僅可以應(yīng)用于 C 語(yǔ)言。它目前也不僅僅只是可以用在 linux 中。它也是可以跨平臺(tái)的應(yīng)用。那么這個(gè) makefile 文件的結(jié)構(gòu)是什么?其實(shí)比較簡(jiǎn)單。目標(biāo): 依賴(lài)1, 依賴(lài)2, …… 編譯命令
filterIndexed 操作符定義和 filter 幾乎是一樣的。他們之前唯一的區(qū)別是 filterIndexed 篩選條件的lambda 表達(dá)式多暴露一個(gè)參數(shù)那就是元素在集合中的 index。也就是外部可以拿到這個(gè)元素以及這個(gè)元素的 index. 特別適合需要集合元素 index 參與篩選條件的 case。源碼定義public inline fun <T> Iterable<T>.filterIndexed(predicate: (index: Int, T) -> Boolean): List<T> { return filterIndexedTo(ArrayList<T>(), predicate)}public inline fun <T, C : MutableCollection<in T>> Iterable<T>.filterIndexedTo(destination: C, predicate: (index: Int, T) -> Boolean): C { forEachIndexed { index, element -> if (predicate(index, element)) destination.add(element) } return destination}public inline fun <T> Iterable<T>.forEachIndexed(action: (index: Int, T) -> Unit): Unit { var index = 0 for (item in this) action(index++, item)}源碼解析首先,要了解 filterIndexed 實(shí)現(xiàn)原理還需要涉及兩個(gè)操作符: filterIndexedTo、forEachIndexed。從整體上可以看出 filterIndexed 是一個(gè) Iterable<T> 的擴(kuò)展函數(shù)并且是一個(gè)內(nèi)聯(lián)函數(shù),該函數(shù)接收一個(gè)以接收Int 類(lèi)型和接收 T 類(lèi)型兩個(gè)參數(shù)返回一個(gè) Boolean 類(lèi)型的 lambda 表達(dá)式 predicate 作為參數(shù),所以它還是一個(gè)高階函數(shù),返回一個(gè) List<T> 集合。然后,大部分實(shí)現(xiàn)的原理和 filter 類(lèi)似,filterIndexedTo 和 filterIndexed 類(lèi)似,唯一可以說(shuō)下的就是index,index 實(shí)際上是 forEachIndexed 內(nèi)部的一個(gè)迭代自增計(jì)數(shù)器,可以在內(nèi)部每次迭代,就會(huì)計(jì)數(shù)器就會(huì)自增一次,并且把這個(gè) index 回調(diào)到外部。使用場(chǎng)景fun main(args: Array<String>) { val numberList = listOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10) val newNumberList = numberList.filterIndexed { index, number -> index < 5 && number % 2 == 0 //篩選出集合中前五個(gè)元素中是偶數(shù)的數(shù) } newNumberList.forEach { print("$it ") }}
在Ruby中我們使用"變量名稱(chēng) = 名稱(chēng)的值"這種形式來(lái)為變量進(jìn)行賦值操作。下面是一些創(chuàng)建不同類(lèi)型變量的例子:實(shí)例:name = "小明"@cars = ['Toyota', 'BMW','Benz']@@color = 'red'$global_variable = 10我們可以通過(guò)class方法查看這個(gè)變量是什么類(lèi)型的變量(換種說(shuō)法,查看這個(gè)變量所屬的類(lèi)是什么)。實(shí)例:> count = 10=> 10> count.class=> Integer解釋?zhuān)翰煌?Java 和 C 等所謂的強(qiáng)變量和靜態(tài)變量類(lèi)型,在聲明變量的時(shí)候必須定義變量類(lèi)型,此類(lèi)型的編程語(yǔ)言在定義變量之后不能更改變量的類(lèi)型。這個(gè)是 C 語(yǔ)言的例子:int count = 10; Ruby 是一種動(dòng)態(tài)的語(yǔ)言,創(chuàng)建變量無(wú)需定義變量類(lèi)型,取而代之的是 Ruby 的解釋器查看分配給變量值的類(lèi)型,并動(dòng)態(tài)計(jì)算出變量的類(lèi)型。這樣做的優(yōu)點(diǎn)是,聲明了變量之后,我們可以在之后的代碼中動(dòng)態(tài)更改變量而無(wú)需去關(guān)心它的類(lèi)型下面我們來(lái)了解在 Ruby 中都有哪幾種變量:
在每個(gè)類(lèi)中,您可以定義實(shí)例方法(instance methods)。每個(gè)方法都是功能的一部分,可以從類(lèi)內(nèi)部調(diào)用(取決于訪問(wèn)約束)。這些實(shí)例方法又可以訪問(wèn)對(duì)象的實(shí)例變量,從而可以訪問(wèn)對(duì)象的狀態(tài)。對(duì)象通過(guò)發(fā)送消息來(lái)調(diào)用方法,該消息包含方法的名稱(chēng)以及該方法所需要的任何參數(shù),當(dāng)對(duì)象接收到消息時(shí),他會(huì)在自己的類(lèi)中查找對(duì)應(yīng)的方法,如果找到則執(zhí)行該方法。聽(tīng)起來(lái)雖然很復(fù)雜,但是實(shí)際使用起來(lái)很自然,下面是一些方法的調(diào)用(示例中箭頭顯示表達(dá)式返回的值)實(shí)例:"gin joint".length ? 9"Rick".index("c") ? 2-1942.abs ? 1942sam.play(aSong) ? "duh dum, da dum de dum ..."解釋?zhuān)核悬c(diǎn)之前的內(nèi)容成為接收者,點(diǎn)之后的成為要調(diào)用的方法;第一個(gè)示例詢(xún)問(wèn)一個(gè)字符串的長(zhǎng)度;第二個(gè)示例詢(xún)問(wèn)一個(gè)字符串其字母’c’的索引;第三個(gè)示例計(jì)算一個(gè)數(shù)字的絕對(duì)值;最后一個(gè),請(qǐng)sam給大家播放一首歌。
將一維的最內(nèi)層的循環(huán)轉(zhuǎn)移到外部循環(huán)迭代器,使得 NumPy 的矢量化操作在處理更大規(guī)模數(shù)據(jù)時(shí)變得更有效率。簡(jiǎn)單來(lái)說(shuō),當(dāng)指定 flags=['external_loop'] 時(shí),將返回一維數(shù)組而并非單個(gè)元素。具體來(lái)說(shuō),當(dāng) ndarray 的順序和遍歷的順序一致時(shí),將所有元素組成一個(gè)一維數(shù)組返回;當(dāng) ndarray 的順序和遍歷的順序不一致時(shí),返回每次遍歷的一維數(shù)組。下面通過(guò)具體案例來(lái)理解這句話(huà):案例對(duì)于上述創(chuàng)建的 arr,是行優(yōu)先順序的數(shù)組。當(dāng)我們指定遍歷順序?yàn)镃(行優(yōu)先,與定義的順序一致),指定 flags=["external_loop"],則有:for i in np.nditer(arr, flags=['external_loop'], order='C'): print(i)打印結(jié)果為:[0 1 2 3 4 5]可以看到,該案例中,把全部元素組成一個(gè)一維數(shù)組,并返回。案例當(dāng)我們指定遍歷順序?yàn)镕(列優(yōu)先),指定 flags=["external_loop"],則有:for i in np.nditer(arr, flags=['external_loop'], order='F'): print(i)打印結(jié)果為:[0 3][1 4][2 5]可以看到,該案例中,返回每次遍歷的一維數(shù)組。
在默認(rèn)情況下,numpy.nditer 迭代器返回的元素順序,是和數(shù)組內(nèi)存布局一致的,這樣做是為了提升訪問(wèn)的效率,默認(rèn)是行序優(yōu)先。案例例如,我們對(duì)于新創(chuàng)建的 2×3 的數(shù)組,利用 nditer 迭代器進(jìn)行順序訪問(wèn):arr = np.arange(6).reshape(2,3)arrOut: array([[0, 1, 2], [3, 4, 5]])for i in np.nditer(arr): print(i, end=" ")打印結(jié)果為:0 1 2 3 4 5 可以看到,在不增加其他設(shè)置的情況下,默認(rèn)的打印順序是行序優(yōu)先(即 C-order)。在不改變內(nèi)部布局的情況下,通過(guò)該方式進(jìn)行遍歷,并不會(huì)改變順序,例如我們通過(guò)迭代上述數(shù)組的轉(zhuǎn)置來(lái)證明這一點(diǎn)。for i in np.nditer(arr.T): print(i, end=" ")打印結(jié)果為:0 1 2 3 4 5 從上述結(jié)果可以看出,轉(zhuǎn)置方法并未改變數(shù)組元素的存儲(chǔ)順序。相對(duì)應(yīng)的,我們利用 copy 方法,顯式地更改內(nèi)存順序,nditer 迭代器的遍歷解雇也會(huì)發(fā)生響應(yīng)的變化:for i in np.nditer(arr.T.copy("C")): print(i, end=" ")打印結(jié)果為:0 3 1 4 2 5
Ruby通過(guò) 子類(lèi) < 基/父類(lèi) 這種形式來(lái)實(shí)現(xiàn)繼承。實(shí)例:class Person def name "My name is Andrew" endendclass Member < Personendputs Member.new.name# ---- 輸出結(jié)果 ----My name is Andrew解釋?zhuān)荷厦娴睦又?,?lèi)Member繼承了類(lèi)Person,所以Member增加了名為name的實(shí)例方法。繼承不光可以繼承實(shí)例方法,同樣也可以繼承類(lèi)方法。實(shí)例:class Person def self.say_hello "Hello" end def name "My name is Andrew" endendclass Member < Personendputs Member.say_hello# ---- 輸出結(jié)果 ----HelloTips:在Ruby中每個(gè)類(lèi)只能繼承一次,不能多重繼承。不過(guò)我們可以通過(guò)混入的方式,將模塊中的方法混入進(jìn)類(lèi)中,從而達(dá)到多重繼承的效果。注意事項(xiàng):我們所指的多重繼承是這樣的形式:class A inherits class Bclass A inherits class C而不是:class A inherits class Bclass B inherits class C當(dāng)繼承的類(lèi)中所含的方法和自身方法名相同的時(shí)候,保留自身的方法,忽略繼承的方法。實(shí)例:class Person def name "My name is Person" end endclass Member < Person def name "My name is Member" end endputs Member.new.name# ---- 輸出結(jié)果 ----My name is Member
NumPy 是一個(gè)運(yùn)行速度非??斓臄?shù)學(xué)庫(kù),主要包含如下能力:一個(gè)高效的 N 維數(shù)組對(duì)象 ndarray;廣播功能函數(shù),無(wú)須循環(huán)即可對(duì)數(shù)組進(jìn)行快速運(yùn)算;讀寫(xiě)磁盤(pán)以及操作內(nèi)存映射文件;一個(gè)用于集成 C / C++ / Fortran 代碼的工具;線性代數(shù)、傅里葉變換、隨機(jī)數(shù)生成等功能。其中 ndarray 對(duì)象是 NumPy 包的核心,ndarray 對(duì)象和標(biāo)準(zhǔn)的 Python 序列數(shù)據(jù)結(jié)構(gòu)的顯著區(qū)別在于:ndarray 對(duì)象在創(chuàng)建時(shí)有固定的大小,這一點(diǎn)不同于 Python 列表。ndarray 對(duì)象中的元素都具有相同的數(shù)據(jù)類(lèi)型,因此在存儲(chǔ)器中將具有相同的大小ndarray 對(duì)象便于對(duì)大量據(jù)進(jìn)行高級(jí)數(shù)學(xué)和其他類(lèi)型的操作。在大數(shù)據(jù)時(shí)代,對(duì)幾百萬(wàn)甚至更大的數(shù)據(jù)進(jìn)行頻繁的循環(huán)迭代計(jì)算,于每一個(gè)數(shù)據(jù)開(kāi)發(fā)者而言都是一場(chǎng)巨大的災(zāi)難,而 Numpy 利用矢量化運(yùn)算,可以有效地避免這一點(diǎn)。
指令含義ctrl+w c/q關(guān)閉當(dāng)前窗口/最后一個(gè)窗口時(shí)退ctrl+w s上下分割當(dāng)前打開(kāi)的文件:sp filename上下分割,并打開(kāi)一個(gè)新的文件ctrl+w v左右分割當(dāng)前打開(kāi)的文件:vsp filename左右分割,并打開(kāi)一個(gè)新的文件使用垂直分屏方式打開(kāi),并上下分割當(dāng)前打開(kāi)的文件:將當(dāng)前打開(kāi)的文件進(jìn)行上下分割,并打開(kāi)一個(gè)新的文件:
字符串的應(yīng)用非常廣泛,所以在 C 語(yǔ)言的標(biāo)準(zhǔn)函數(shù)庫(kù)中,提供了相關(guān)的支持。這里我們只是介紹了標(biāo)準(zhǔn)函數(shù)庫(kù)中的大約四分之一的常用函數(shù)的使用。這些函數(shù)的使用中,請(qǐng)大家記住字符串是由字符數(shù)組組成這一特性,在拼接,復(fù)制等等操作的時(shí)候,確認(rèn)目標(biāo)數(shù)組的大小是不是可以足夠的位置裝載相關(guān)的元素。
因?yàn)?C 語(yǔ)言與需要編譯之后才能執(zhí)行,所以需要對(duì)變量指定類(lèi)型后才能使用。因?yàn)?C 語(yǔ)言會(huì)對(duì)不同的數(shù)據(jù)類(lèi)型分配不同的內(nèi)存大小,這就是為什么 C 語(yǔ)言需要指定數(shù)據(jù)類(lèi)型,而諸如 PHP, Python 這樣的語(yǔ)言不需要指定。指定大小的好處是可以讓程序處理起來(lái)更快,內(nèi)存的開(kāi)銷(xiāo)更小。變量類(lèi)型列表類(lèi)型存儲(chǔ)長(zhǎng)度數(shù)值范圍char1 byte-128 to 127unsigned char1 byte0 to 255signed char1 byte-128 to 127int4 bytes-2,147,483,648 to 2,147,483,647unsigned int4 bytes0 to 4,294,967,295short2 bytes-32,768 to 32,767unsigned short2 bytes0 to 65,535long8 bytes-9223372036854775808 to 9223372036854775807unsigned long8 bytes0 to 18446744073709551615對(duì)于用科學(xué)計(jì)數(shù)法表示的類(lèi)型還涉及到小數(shù)可以表示的精度,也就是有效數(shù)字。請(qǐng)看下面的表格:類(lèi)型存儲(chǔ)長(zhǎng)度數(shù)值范圍小數(shù)點(diǎn)后的位數(shù)float4 byte1.2E-38 to 3.4E+386double8 byte2.3E-308 to 1.7E+30815long double10 byte3.4E-4932 to 1.1E+493219這里有一個(gè)程序可以輸出你的計(jì)算機(jī)中的不同數(shù)據(jù)結(jié)構(gòu)在內(nèi)存中所占用的內(nèi)存的位數(shù)。對(duì)于不同的硬件這個(gè)返回值是不同的。382將上面的程序粘貼到文本編輯器中,然后以 test.c 文件名保存。在終端命令行中輸入gcc test.c -o test編譯完成后./test來(lái)執(zhí)行上面的程序。我的樹(shù)莓派4上輸出的結(jié)果如下:CHAR_BIT : 8CHAR_MAX : 255CHAR_MIN : 0INT_BIT : 4INT_MAX : 2147483647INT_MIN : -2147483648LONG_BIT : 4LONG_MAX : 2147483647LONG_MIN : -2147483648SCHAR_BIT : 1SCHAR_MAX : 127SCHAR_MIN : -128SHRT_BIT : 2SHRT_MAX : 32767SHRT_MIN : -32768UCHAR_BIT : 1UCHAR_MAX : 255UINT_MAX : 4294967295ULONG_BIT : 4ULONG_MAX : 4294967295USHRT_MAX : 65535Storage size for float : 4Strage size for double : 8FLT_MAX : 3.40282e+38FLT_MIN : 1.17549e-38-FLT_MAX : -3.40282e+38-FLT_MIN : -1.17549e-38DBL_MAX : 1.79769e+308DBL_MIN : 2.22507e-308-DBL_MAX : -1.79769e+308Float precision value : 6Double precision value : 15這臺(tái)單板計(jì)算機(jī)的處理器是 arm64。在樹(shù)莓派2上的輸出結(jié)果如下:CHAR_BIT : 8CHAR_MAX : 255CHAR_MIN : 0INT_BIT : 4INT_MAX : 2147483647INT_MIN : -2147483648LONG_BIT : 4LONG_MAX : 2147483647LONG_MIN : -2147483648SCHAR_BIT : 1SCHAR_MAX : 127SCHAR_MIN : -128SHRT_BIT : 2SHRT_MAX : 32767SHRT_MIN : -32768UCHAR_BIT : 1UCHAR_MAX : 255UINT_MAX : 4294967295ULONG_BIT : 4ULONG_MAX : 4294967295USHRT_MAX : 65535Storage size for float : 4Strage size for double : 8FLT_MAX : 3.40282e+38FLT_MIN : 1.17549e-38-FLT_MAX : -3.40282e+38-FLT_MIN : -1.17549e-38DBL_MAX : 1.79769e+308DBL_MIN : 2.22507e-308-DBL_MAX : -1.79769e+308Float precision value : 6Double precision value : 15這臺(tái)單板計(jì)算機(jī)的處理器是 arm32。在我的筆記本電腦上運(yùn)行的結(jié)果如下:CHAR_BIT : 8CHAR_MAX : 127CHAR_MIN : -128INT_BIT : 4INT_MAX : 2147483647INT_MIN : -2147483648LONG_BIT : 8LONG_MAX : 9223372036854775807LONG_MIN : -9223372036854775808SCHAR_BIT : 1SCHAR_MAX : 127SCHAR_MIN : -128SHRT_BIT : 2SHRT_MAX : 32767SHRT_MIN : -32768UCHAR_BIT : 1UCHAR_MAX : 255UINT_MAX : 4294967295ULONG_BIT : 8ULONG_MAX : 18446744073709551615USHRT_MAX : 65535Storage size for float : 4Strage size for double : 8FLT_MAX : 3.40282e+38FLT_MIN : 1.17549e-38-FLT_MAX : -3.40282e+38-FLT_MIN : -1.17549e-38DBL_MAX : 1.79769e+308DBL_MIN : 2.22507e-308-DBL_MAX : -1.79769e+308Float precision value : 6Double precision value : 15這臺(tái)電腦的處理器是 x86_64 架構(gòu),也就是大家在市場(chǎng)上買(mǎi)到的家用電腦的架構(gòu)。大家可以看到這里有些數(shù)值是一樣的,但是有些卻不同。這就是計(jì)算機(jī)硬件上的差異,大家在使用 C 語(yǔ)言給硬件編程的時(shí)候一定要考慮到這點(diǎn)影響。
使用 while 循環(huán)顯式的使用 next、StopIteration 完成對(duì) stack 的遍歷,代碼如下:generator = stackGenerate(stack)while True: try: item = next(generator) print(item) except StopIteration: break在第 1 行,stackGenerate(stack) 返回一個(gè)遍歷堆棧的生成器在第 4 行,next(generator) 獲取生成器的輸出在第 6 行,當(dāng)生成器輸出結(jié)束后,拋出異常 StopIteration程序依次壓入 ‘a(chǎn)’、‘b’、‘c’,遍歷時(shí)以壓入相反的順序輸出,結(jié)果如下:cba
本章節(jié)介紹了 Redis 最基礎(chǔ)的 SDS 數(shù)據(jù)結(jié)構(gòu),有兩點(diǎn)需要重點(diǎn)關(guān)注:(1)Redis底層對(duì) C 語(yǔ)言自帶數(shù)據(jù)結(jié)構(gòu)進(jìn)行了封裝優(yōu)化。(2)Redis 作為內(nèi)存數(shù)據(jù)庫(kù),不能避免頻繁的修改和查詢(xún)操作,所以在設(shè)計(jì)最初,各種數(shù)據(jù)結(jié)構(gòu)和操作實(shí)現(xiàn)的核心目的就是為了追求速度,遍歷和內(nèi)存分配等耗時(shí)的操作是難以忍受的。
通過(guò)索引 [] 獲取字符串中指定位置的字符,示例如下:>>> s = 'imooc'>>> s[0]'i'>>> s[1]'m'>>> s[2]'o'>>> s[3]'o'>>> s[4]'c'在 Python 中,單個(gè)字符也被當(dāng)作字符串來(lái)處理,即該字符串只包含一個(gè)字符在第 2 行,獲取字符串 s 的第 0 個(gè)字符 ‘i’在第 4 行,獲取字符串 s 的第 1 個(gè)字符 ‘m’
os.listdir(path) 的功能是列出指定目錄下的文件名:參數(shù) path,path 是目錄的路徑返回值,返回一個(gè)字符串列表,列表是目錄下的文件名該函數(shù)的使用示例:>>> import os>>> os.listdir('C:\\Program Files')['Common Files', 'desktop.ini', 'Git', 'IIS', 'Intel', 'Internet Explorer', 'JetBrains', 'Microsoft Help Viewer', 'Microsoft Office', 'Microsoft SQL Server', 'Microsoft Visual Studio 9.0', 'Microsoft.NET', 'Mozilla Firefox', 'Office', 'Oracle', 'PuTTY', 'Sublime Text 2', 'tcc', 'Typora', 'Uninstall Information', 'Windows admin', 'Windows Identity Foundation', 'Windows Kits', 'Windows Mail', 'Windows Media Player']
Http 協(xié)議請(qǐng)求報(bào)文的本質(zhì)就是一堆字符串,只是這堆字符是有格式的,發(fā)送方跟接收方都需要按照這個(gè)格式來(lái)拼接和拆解內(nèi)容。我們要實(shí)現(xiàn)一個(gè) Web 服務(wù),了解這個(gè)是最基本的要素。以下截圖的報(bào)文是通過(guò) tcpflow(一款功能強(qiáng)大的、基于命令行的免費(fèi)開(kāi)源工具)在 Linux 系統(tǒng)抓包獲取的。sudo tcpflow -c port 8080
先查看 course 表所有數(shù)據(jù):SELECT * FROM course;查詢(xún)結(jié)果如下圖:以表 course 為例,需要查出所有課程教師相關(guān)信息,按照 teacher_id 字段分組可去除重復(fù)數(shù)據(jù): SELECT teacher_id FROM course GROUP BY teacher_id;查詢(xún)結(jié)果如下圖:根據(jù)上面分組結(jié)果還可以使用 LEFT JOIN 連接查詢(xún)分組:SELECT c.teacher_id,t.* FROM course c LEFT JOIN teacher t ON c.teacher_id=t.id GROUP BY c.teacher_id;執(zhí)行結(jié)果如下圖:
C 語(yǔ)言中的標(biāo)準(zhǔn)輸入輸出包含 3 部分。標(biāo)準(zhǔn)輸入,標(biāo)準(zhǔn)輸出,標(biāo)準(zhǔn)錯(cuò)誤輸出。表中列舉了標(biāo)準(zhǔn)輸入輸出和與之關(guān)聯(lián)的物理設(shè)備。輸入輸出設(shè)備標(biāo)準(zhǔn)輸入鍵盤(pán)標(biāo)準(zhǔn)輸出顯示器屏幕標(biāo)準(zhǔn)錯(cuò)誤輸出顯示器屏幕標(biāo)準(zhǔn)錯(cuò)誤輸出就是當(dāng)你程序出錯(cuò)的時(shí)候在屏幕上看到的信息。
請(qǐng)書(shū)寫(xiě) SQL 語(yǔ)句,查詢(xún)imooc_user表中每一個(gè)用戶(hù)姓名和該用戶(hù)所參加課程的名稱(chēng)。分析:由題干可知,查詢(xún)的結(jié)果應(yīng)是用戶(hù)姓名以及參加課程,因此 imooc_user 表應(yīng)該作為保留表;考慮到使用左連接,所以 imooc_user 表是左表,imooc_class 表作為右表。語(yǔ)句:整理可得語(yǔ)句如下:SELECT username,class_name FROM imooc_user LEFT OUTER JOIN imooc_class ON imooc_user.class_id = imooc_class.id;結(jié)果如下:+----------+---------------+| username | class_name |+----------+---------------+| pedro | SQL必知必會(huì) || peter | SQL必知必會(huì) || faker | C語(yǔ)言入門(mén) || lucy | JVM花落知多少 || jery | <null> |+----------+---------------+
numpy.linalg.det() 函數(shù)計(jì)算輸入矩陣的行列式。行列式在線性代數(shù)中是非常有用的值。 它從方陣的對(duì)角元素計(jì)算。 對(duì)于 2×2 矩陣,它是左上和右下元素的乘積與其他兩個(gè)的乘積的差。換句話(huà)說(shuō),對(duì)于矩陣 [[a,b],[c,d]],行列式計(jì)算為 ad-bc。 較大的方陣被認(rèn)為是 2×2 矩陣的組合。案例M = np.array([[6, 2, 1], [4, -2, 15], [12, 8, 7]]) Mout: array([[ 6, 2, 1], [ 4, -2, 15], [12, 8, 7]])求解矩陣 M 的行列式:np.linalg.det(M)out: -444
for 語(yǔ)句是 C 語(yǔ)言循環(huán)語(yǔ)句中應(yīng)用最為廣泛的循環(huán)語(yǔ)句。語(yǔ)句在使用中主要由四個(gè)步驟構(gòu)成,初始化控制變量,編寫(xiě)循環(huán)條件,編寫(xiě)控制變量的變化規(guī)則,寫(xiě)循環(huán)體。為什么說(shuō)是編寫(xiě)控制變量的變化規(guī)則呢?因?yàn)殡m然很多情況下我們使用了自減或者自增,但是其實(shí)還有更多的控制變量的變化方式,比如偶數(shù)變化,奇數(shù)變化,指數(shù)變化等等。
安裝包下載完成后,打開(kāi)安裝包,開(kāi)始安裝。與常用軟件安裝的流程基本相同。點(diǎn)擊下一步 -> (選擇安裝目錄)下一步 -> 等待安裝完成即可完成安裝。選擇安裝目錄,這里我們采用默認(rèn)的 C:\Program Files\Java\jdk-15.0.1 ,直接點(diǎn)擊下一步。請(qǐng)記住這里的安裝目錄,我們將在配置環(huán)境變量時(shí)用到。點(diǎn)擊下一步后開(kāi)始安裝,等待安裝完成。安裝完成,點(diǎn)擊關(guān)閉按鈕。
一般情況下我們通過(guò)前兩種方法就可以很快安裝成功,源碼安裝稍顯麻煩,如果有興趣的可以參考如下步驟:這種方法需要自己下載安裝包、解壓、編譯等一步一步進(jìn)行操作,我們一起看下:(1) 先下載 git 依賴(lài)的包[root@localhost opt]# yum -y install zlib-devel openssl-devel perl cpio expat-devel gettext-devel(2) wget 下載 git 安裝包[root@localhost opt]# wget https://mirrors.edge.kernel.org/pub/software/scm/git/git-2.9.5.tar.gz--2020-09-03 17:38:22-- https://mirrors.edge.kernel.org/pub/software/scm/git/git-2.9.5.tar.gz正在解析主機(jī) mirrors.edge.kernel.org... 147.75.95.133, 2604:1380:3000:1500::1Connecting to mirrors.edge.kernel.org|147.75.95.133|:443... 已連接。已發(fā)出 HTTP 請(qǐng)求,正在等待回應(yīng)... 200 OK長(zhǎng)度:5928730 (5.7M) [application/x-gzip]Saving to: `git-2.9.5.tar.gz'100%[======================================>] 5,928,730 1.43M/s in 5.0s 2020-09-03 17:38:29 (1.13 MB/s) - `git-2.9.5.tar.gz' saved [5928730/5928730]出現(xiàn)以上信息則說(shuō)明下載成功,我們看下當(dāng)前目錄是否有下載的 tar 包。(3)查看當(dāng)前目錄的文件[root@localhost opt]# lsgit-2.9.5.tar.gzgit-2.9.5.tar.gz 就是我們下載的 git 安裝包,說(shuō)明已經(jīng)下載成功。(4)解壓壓縮包接下來(lái)需要將壓縮包解壓,執(zhí)行如下命令:[root@localhost opt]# tar zxvf git-2.9.5[root@localhost opt]# lsgit-2.9.5 git-2.9.5.tar.gz可以看到,解壓后當(dāng)前目錄已經(jīng)多了一個(gè)解壓后的文件夾,之后我們都在這個(gè)文件夾進(jìn)行安裝操作。(5)安裝 autoconf[root@localhost opt]# yum install autoconf(6)進(jìn)入安裝文件目錄,執(zhí)行 autoconf:[root@localhost opt]# cd git-2.9.5[root@localhost git-2.9.5]# autoconf(7)繼續(xù)執(zhí)行如下命令:[root@localhost git-2.9.5]# ./configure --with-curl=/usr/localconfigure: Setting lib to 'lib' (the default)configure: Will try -pthread then -lpthread to enable POSIX Threads.configure: CHECKS for site configurationchecking for gcc... nochecking for cc... nochecking for cl.exe... noconfigure: error: in `/opt/git-2.9.5':configure: error: no acceptable C compiler found in $PATHSee `config.log' for more details(8)執(zhí)行編譯:由于 Git 是使用 C 寫(xiě)的,因此需要進(jìn)行編譯操作。[root@localhost git-2.9.5]# make CC credential-store.o/bin/sh: cc: command not foundmake: *** [credential-store.o] 錯(cuò)誤 127咦!好像報(bào)錯(cuò)了,這是怎么回事?別慌,由報(bào)錯(cuò)信息可以知道缺少某個(gè)執(zhí)行文件。我們需要繼續(xù)安裝 gcc 等相關(guān)包,才可以執(zhí)行 make。那么我們繼續(xù)安裝:(9)安裝 C 環(huán)境[root@localhost git-2.9.5]# yum -y install gcc gcc-c++ libstdc++-devel(10)重新執(zhí)行 make 命令即可成功。[root@localhost git-2.9.5]# make[root@localhost git-2.9.5]# make install(11)編譯完成后,我們用 git 命令驗(yàn)證下是否安裝成功[root@localhost git-2.9.5]# git --versiongit version 2.9.5現(xiàn)在提示正常,顯示當(dāng)前 Git 版本是 2.9.5,也就是我們安裝的版本。至此,說(shuō)明已經(jīng)安裝成功。但是,別忘了配置當(dāng)前用戶(hù)身份標(biāo)識(shí),因?yàn)槊總€(gè) Git 提交都使用此信息,并且將它永久地記錄到您開(kāi)始創(chuàng)建的提交中。(12)配置身份信息[root@localhost git-2.9.5]# git config --global user.name "Your Name"[root@localhost git-2.9.5]# git config --global user.email "Your Email" <font color=#DC143C>將Your Name 和Your Email分別用你自己的名稱(chēng)和郵箱替換即可。</font>到這里,CentOS7 操作系統(tǒng) Git 的安裝就已經(jīng)結(jié)束了。
場(chǎng)景一: lambda 表達(dá)式與集合一起使用,是最常見(jiàn)的場(chǎng)景,可以各種篩選、映射、變換操作符和對(duì)集合數(shù)據(jù)進(jìn)行各種操作,非常靈活,相信使用過(guò) RxJava 中的開(kāi)發(fā)者已經(jīng)體會(huì)到這種快感,沒(méi)錯(cuò) Kotlin 在語(yǔ)言層面,無(wú)需增加額外庫(kù),就給你提供了支持函數(shù)式編程 API:package com.imooc.kotlin.lambdafun main(args: Array<String>) { val nameList = listOf("Kotlin", "Java", "Python", "JavaScript", "Scala", "C", "C++", "Go", "Swift") nameList.filter { it.startsWith("K") }.map { "$it is a very good language" }.forEach { println(it) }}場(chǎng)景二:替代原有匿名內(nèi)部類(lèi),但是需要注意一點(diǎn)就是只能替代含有單抽象方法的類(lèi): findViewById(R.id.submit).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { ... } });用 kotlin lambda 實(shí)現(xiàn):findViewById(R.id.submit).setOnClickListener{ ...}場(chǎng)景三:定義Kotlin擴(kuò)展函數(shù)或者說(shuō)需要把某個(gè)操作或函數(shù)當(dāng)做值傳入的某個(gè)函數(shù)的時(shí)候:fun Context.showDialog(content: String = "", negativeText: String = "取消", positiveText: String = "確定", isCancelable: Boolean = false, negativeAction: (() -> Unit)? = null, positiveAction: (() -> Unit)? = null) { AlertDialog.build(this) .setMessage(content) .setNegativeButton(negativeText) { _, _ -> negativeAction?.invoke() } .setPositiveButton(positiveText) { _, _ -> positiveAction?.invoke() } .setCancelable(isCancelable) .create() .show()}fun Context.toggleSpFalse(key: String, func: () -> Unit) { if (!getSpBoolean(key)) { saveSpBoolean(key, true) func() }}fun <T : Any> Observable<T>.subscribeKt(success: ((successData: T) -> Unit)? = null, failure: ((failureError: RespException?) -> Unit)? = null): Subscription? { return transformThread() .subscribe(object : SBRespHandler<T>() { override fun onSuccess(data: T) { success?.invoke(data) } override fun onFailure(e: RespException?) { failure?.invoke(e) } })}
從集合的第一項(xiàng)開(kāi)始去掉滿(mǎn)足條件元素,這樣操作一直持續(xù)到出現(xiàn)第一個(gè)不滿(mǎn)足條件元素出現(xiàn)為止,返回剩余元素(可能剩余元素有滿(mǎn)足條件的元素)。源碼定義public inline fun <T> Iterable<T>.dropWhile(predicate: (T) -> Boolean): List<T> { var yielding = false//初始化標(biāo)志位false val list = ArrayList<T>()//創(chuàng)建一個(gè)新的可變集合 for (item in this)//遍歷原集合 if (yielding)//該標(biāo)志一直為false直到,不符合lambda表達(dá)式外部傳入條件時(shí),該標(biāo)記為置為true,才開(kāi)始往新集合添加元素 list.add(item) else if (!predicate(item)) {//判斷不符合外部傳入的條件,才開(kāi)始往新集合添加元素,標(biāo)記置為true, //這樣就滿(mǎn)足了需求,一開(kāi)始符合條件元素不會(huì)被添加到新集合中,不符合條件才開(kāi)始加入新集合,這樣產(chǎn)生新集合相對(duì)于原集合而言也就是刪除符合條件元素直到出現(xiàn)不符合條件的為止 list.add(item) yielding = true } return list}原理圖解使用場(chǎng)景適用于去掉集合中前半部分具有相同特征的元素場(chǎng)景。fun main(args: Array<String>) { val strList = listOf("java", "javaScript", "kotlin", "C", "C++", "javaFx","python", "Swift", "Go", "Scala") strList.dropWhile { it.startsWith("java") }.forEach { print("$it ") }}
默認(rèn)情況下,在我們點(diǎn)擊 Run 后,Android Studio 會(huì)編譯應(yīng)用的調(diào)試版本,不過(guò)這僅供在開(kāi)發(fā)期間使用。要更改 Android Studio 使用的構(gòu)建變體,請(qǐng)?jiān)诓藛螜谥幸来芜x擇 Build > Select Build Variant。對(duì)于不含原生/C++ 代碼的項(xiàng)目Build Variants 面板有兩列:Module 和 Active Build Variant。模塊的 Active Build Variant 值決定了 IDE 部署到連接的設(shè)備并顯示在編輯器中的構(gòu)建變體。要在變體之間切換,請(qǐng)點(diǎn)擊模塊的 Active Build Variant 單元格,然后從列表字段中選擇所需的變體。對(duì)于含有原生/C++ 代碼的項(xiàng)目Build Variants 面板有三列:Module、Active Build Variant 和 Active ABI。模塊的 Active Build Variant 值決定了 IDE 部署到設(shè)備并顯示在編輯器中的構(gòu)建變體。對(duì)于原生模塊,Active ABI 值決定了編輯器使用的 ABI,但不會(huì)影響部署的內(nèi)容。要更改構(gòu)建變體或 ABI,請(qǐng)點(diǎn)擊 Active Build Variant 或 Active ABI 列的單元格,然后從列表中選擇所需的變體或 ABI。在我們更改所選內(nèi)容后,IDE 會(huì)自動(dòng)同步我們的項(xiàng)目。更改應(yīng)用或庫(kù)模塊的任一列都會(huì)將更改應(yīng)用于所有相關(guān)行。
在前面已經(jīng)介紹,接口可以描述函數(shù)、對(duì)象的方法或者對(duì)象的屬性。有時(shí)希望一個(gè)對(duì)象同時(shí)具有上面提到多種類(lèi)型,比如一個(gè)對(duì)象可以當(dāng)做函數(shù)使用,同時(shí)又具有屬性和方法。interface Counter { (start: number): string; interval: number; reset(): void;}function getCounter(): Counter { let counter = function (start: number) { } as Counter; counter.interval = 123; counter.reset = function () { }; return counter;}let c = getCounter();c(10);c.reset();c.interval = 5.0;代碼解釋?zhuān)旱?1 行,聲明一個(gè)接口,如果只有 (start: number): string 一個(gè)成員,那么這個(gè)接口就是函數(shù)接口,同時(shí)還具有其他兩個(gè)成員,可以用來(lái)描述對(duì)象的屬性和方法,這樣就構(gòu)成了一個(gè)混合接口。第 7 行,創(chuàng)建一個(gè) getCounter() 函數(shù),它的返回值是 Counter 類(lèi)型的。let counter = function (start: number) { } as Counter;第 8 行,通過(guò)類(lèi)型斷言,將函數(shù)對(duì)象轉(zhuǎn)換為 Counter 類(lèi)型,轉(zhuǎn)換后的對(duì)象不但實(shí)現(xiàn)了函數(shù)接口的描述,使之成為一個(gè)函數(shù),還具有 interval 屬性和 reset() 方法。斷言成功的條件是,兩個(gè)數(shù)據(jù)類(lèi)型只要有一方可以賦值給另一方,這里函數(shù)類(lèi)型數(shù)據(jù)不能賦值給接口類(lèi)型的變量,因?yàn)樗痪哂?interval 屬性和 reset() 方法。類(lèi)型斷言在之后的小節(jié)也會(huì)單節(jié)介紹。