Golang 學(xué)習(xí)筆記二 數(shù)組迹炼、切片

一、數(shù)組

《快學(xué) Go 語言》第 4 課 —— 低調(diào)的數(shù)組
Go 語言里面的數(shù)組其實(shí)很不常用裂垦,這是因?yàn)閿?shù)組是定長的靜態(tài)的顺囊,一旦定義好長度就無法更改,而且不同長度的數(shù)組屬于不同的類型蕉拢,之間不能相互轉(zhuǎn)換相互賦值特碳,用起來多有不方便之處。

切片是動(dòng)態(tài)的數(shù)組晕换,是可以擴(kuò)充內(nèi)容增加長度的數(shù)組午乓。當(dāng)長度不變時(shí),它用起來就和普通數(shù)組一樣闸准。當(dāng)長度不同時(shí)益愈,它們也屬于相同的類型,之間可以相互賦值夷家。這就決定了數(shù)組的應(yīng)用領(lǐng)域都廣泛地被切片取代了蒸其。
1.只聲明的話,全部是零值

func main() {
    var a [9]int
    fmt.Println(a)
}

------------
[0 0 0 0 0 0 0 0 0]

三種聲明方式,給初值方式是一樣的

var a = [9]int{1, 2, 3, 4, 5, 6, 7, 8, 9}
var b [10]int = [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
c := [8]int{1, 2, 3, 4, 5, 6, 7, 8}
//[0,10,20,0,0]
array := [5]int{1:10,2:20}

2.下標(biāo)訪問

func main() {
    var squares [9]int
    for i := 0; i < len(squares); i++ {
        squares[i] = (i + 1) * (i + 1)
    }
    fmt.Println(squares)
}

--------------------
[1 4 9 16 25 36 49 64 81]

3.數(shù)組賦值
同樣的子元素類型并且是同樣長度的數(shù)組才可以相互賦值库快,否則就是不同的數(shù)組類型摸袁,不能賦值。數(shù)組的賦值本質(zhì)上是一種淺拷貝操作缺谴,賦值的兩個(gè)數(shù)組變量的值不會(huì)共享但惶。

func main() {
    var a = [9]int{1, 2, 3, 4, 5, 6, 7, 8, 9}
    var b [9]int
    b = a
    a[0] = 12345
    fmt.Println(a)
    fmt.Println(b)
}

--------------------------
[12345 2 3 4 5 6 7 8 9]
[1 2 3 4 5 6 7 8 9]

4.range關(guān)鍵字來遍歷

func main() {
    var a = [5]int{1,2,3,4,5}
    for index := range a {
        fmt.Println(index, a[index])
    }
    for index, value := range a {
        fmt.Println(index, value)
    }
}

------------
0 1
1 2
2 3
3 4
4 5
0 1
1 2
2 3
3 4
4 5

每次循環(huán)迭代, range 產(chǎn)生一對(duì)值湿蛔;索引以及在該索引處的元素值膀曾。如果不需要索引怎么辦,range 的語法要求, 要處理元素, 必須處理索引阳啥。一種思路是把索引賦值給一個(gè)臨時(shí)變量,如 temp , 然后忽略它的值添谊,但Go語言不允許使用無用的局部變量(local variables),因?yàn)檫@會(huì)導(dǎo)致編譯錯(cuò)誤察迟。Go語言中這種情況的解決方法是用 空標(biāo)識(shí)符 (blank identifier)斩狱,即 _ (也就是下劃線)耳高。空標(biāo)識(shí)符可用于任何語法需要變量名但程序邏輯不需要的時(shí)候, 例如, 在循環(huán)里所踊,丟棄不需要的循環(huán)索引, 保留元素值泌枪。

    for _,value := range s1{
        fmt.Println(value)
    }

注意:range創(chuàng)建了每個(gè)元素的副本,而不是直接返回對(duì)該元素的引用秕岛。range總是會(huì)從切片頭部開始迭代碌燕。

5.函數(shù)間傳遞數(shù)組
在函數(shù)間傳遞變量時(shí),總是以值的方式傳遞继薛。如果變量是個(gè)數(shù)組修壕,意味著整個(gè)數(shù)組,不管有多長遏考,都會(huì)完整復(fù)制慈鸠,并傳遞給函數(shù)。在這方面灌具,go語言對(duì)待數(shù)組的方式和其它很多編程語言不同青团,其它語言可能會(huì)隱式地將數(shù)組作為引用或指針對(duì)象傳入被調(diào)用的函數(shù)。

有一種更好且更有效的方法來處理這個(gè)操作稽亏,就是只傳入指向數(shù)組的指針壶冒,只需要復(fù)制8個(gè)字節(jié)的數(shù)據(jù),這樣危險(xiǎn)在于截歉,共享了內(nèi)存胖腾,會(huì)改變?cè)贾怠?/p>

二、切片

《快學(xué) Go 語言》第 5 課 —— 靈活的切片

image.png

上圖中一個(gè)切片變量包含三個(gè)域瘪松,分別是底層數(shù)組的指針咸作、切片的長度 length 和切片的容量 capacity。切片支持 append 操作可以將新的內(nèi)容追加到底層數(shù)組宵睦,也就是填充上面的灰色格子记罚。如果格子滿了,切片就需要擴(kuò)容壳嚎,底層的數(shù)組就會(huì)更換桐智。

形象一點(diǎn)說,切片變量是底層數(shù)組的視圖烟馅,底層數(shù)組是臥室说庭,切片變量是臥室的窗戶。通過窗戶我們可以看見底層數(shù)組的一部分或全部郑趁。一個(gè)臥室可以有多個(gè)窗戶刊驴,不同的窗戶能看到臥室的不同部分。

1.切片的創(chuàng)建有多種方式,我們先看切片最通用的創(chuàng)建方法捆憎,那就是內(nèi)置的 make 函數(shù)

var s1 []int = make([]int, 5, 8)
 var s2 []int = make([]int, 8) // 滿容切片

make 函數(shù)創(chuàng)建切片舅柜,需要提供三個(gè)參數(shù),分別是切片的類型躲惰、切片的長度和容量致份。其中第三個(gè)參數(shù)是可選的,如果不提供第三個(gè)參數(shù)础拨,那么長度和容量相等知举,也就是說切片的滿容的。

使用 make 函數(shù)創(chuàng)建的切片內(nèi)容是「零值切片」太伊,也就是內(nèi)部數(shù)組的元素都是零值。Go 語言還提供了另一個(gè)種創(chuàng)建切片的語法逛钻,允許我們給它賦初值僚焦。使用這種方式創(chuàng)建的切片是滿容的。

func main() {
 var s []int = []int{1,2,3,4,5}  // 滿容的
 fmt.Println(s, len(s), cap(s))
}

---------
[1 2 3 4 5] 5 5

這種寫法曙痘,和數(shù)組的定義非常相似芳悲,注意區(qū)別就在方括號(hào)里是否寫了長度。

    var i1 [5]int = [5]int{1,2,3,4,5}
    var i2 []int = []int{1,2,3,4,5}
    i1 = append(i1, 6)
    i2 = append(i2,7)

編譯不通過边坤,i1用不了append方法名扛,參數(shù)必須是slice

2.切片的賦值
切片的賦值是一次淺拷貝操作,拷貝的是切片變量的三個(gè)域茧痒,你可以將切片變量看成長度為 3 的 int 型數(shù)組肮韧,數(shù)組的賦值就是淺拷貝⊥拷貝前后兩個(gè)變量共享底層數(shù)組弄企,對(duì)一個(gè)切片的修改會(huì)影響另一個(gè)切片的內(nèi)容,這點(diǎn)需要特別注意区拳。

func main() {
 var s1 = make([]int, 5, 8)
 // 切片的訪問和數(shù)組差不多
 for i := 0; i < len(s1); i++ {
  s1[i] = i + 1
 }
 var s2 = s1
 fmt.Println(s1, len(s1), cap(s1))
 fmt.Println(s2, len(s2), cap(s2))

 // 嘗試修改切片內(nèi)容
 s2[0] = 255
 fmt.Println(s1)
 fmt.Println(s2)
}

--------
[1 2 3 4 5] 5 8
[1 2 3 4 5] 5 8
[255 2 3 4 5]
[255 2 3 4 5]

3.append追加
相對(duì)于數(shù)組拘领,切片可以增加長度。當(dāng)append返回時(shí)樱调,會(huì)返回一個(gè)包含修改結(jié)果的新切片约素。函數(shù)append總會(huì)增加新切片的長度,而容量有可能改變笆凌,也有可能不改變圣猎,這取決于被操作切片的可用容量。

slice := []int{10,20,30,40,50}
newSlice := slice[1:3]
newSlice = append(newSlice,60);

因?yàn)閚ewSlice在底層數(shù)組里還有額外容量可用菩颖,append操作將可用元素合并到切片的長度样漆,并對(duì)其進(jìn)行賦值。由于和原始的slice共享同一個(gè)底層數(shù)組晦闰,slice中索引為3的元素值也被改動(dòng)了放祟。

如果切片的底層數(shù)組沒有足夠可用容量鳍怨,append函數(shù)會(huì)創(chuàng)建一個(gè)新的底層數(shù)組,將被引用的現(xiàn)有值復(fù)制到新數(shù)組里跪妥,再追加新值鞋喇。

slice := []int{10,20,30,40}
newSlice = append(slice,50)

函數(shù)append會(huì)自動(dòng)處理底層數(shù)組的容量增長,在切片容量小于1000個(gè)元素時(shí)眉撵,總是會(huì)成倍地增加容量侦香。超過1000時(shí),每次增加25%纽疟。

append可以在一次調(diào)用傳遞多個(gè)追加值罐韩,如果使用...運(yùn)算符,可以將一個(gè)切片所有元素追加到另一個(gè)切片里

s1 := []int{1,2}
s2 := []int{3,4}
append(s1,s2...);

4.切割

func main() {
 var s1 = []int{1,2,3,4,5,6,7}
 // start_index 和 end_index污朽,不包含 end_index
 // [start_index, end_index)
 var s2 = s1[2:5] 
 s2[0] = 0
 fmt.Println(s1, len(s1), cap(s1))
 fmt.Println(s2, len(s2), cap(s2))
}

------------
[1 2 0 4 5 6 7] 7 7
[0 4 5] 3 5

image.png

我們注意到子切片的內(nèi)部數(shù)據(jù)指針指向了數(shù)組的中間位置散吵,而不再是數(shù)組的開頭了。子切片容量的大小是從中間的位置開始直到切片末尾的長度蟆肆,母子切片依舊共享底層數(shù)組矾睦。

子切片語法上要提供起始和結(jié)束位置,這兩個(gè)位置都可選的炎功,不提供起始位置枚冗,默認(rèn)就是從母切片的初始位置開始(不是底層數(shù)組的初始位置),不提供結(jié)束位置蛇损,默認(rèn)就結(jié)束到母切片尾部(是長度線赁温,不是容量線)。使用過 Python 的同學(xué)可能會(huì)問州藕,切片支持負(fù)數(shù)的位置么束世,答案是不支持,下標(biāo)不可以是負(fù)數(shù)床玻。

對(duì)數(shù)組進(jìn)行切割可以轉(zhuǎn)換成切片毁涉,切片將原數(shù)組作為內(nèi)部底層數(shù)組。也就是說修改了原數(shù)組會(huì)影響到新切片锈死,對(duì)切片的修改也會(huì)影響到原數(shù)組贫堰。

func main() {
    var a = [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
    var b = a[2:6]
    fmt.Println(b)
    a[4] = 100
    fmt.Println(b)
}

-------
[3 4 5 6]
[3 4 100 6]

5.切割的第三個(gè)參數(shù)

source := []string{"apple","orange","plum","banana","grape"};
slice := source[2:3]//plum1個(gè)元素,到結(jié)尾待牵,3個(gè)容量
slice := source[2:3:4]//也是一個(gè)1元素其屏,不過有4-2=2個(gè)容量

使用第3個(gè)參數(shù)將長度和容量保持一致后,再使用append操作就會(huì)創(chuàng)建新的底層數(shù)組缨该,從而和原底層數(shù)組分離偎行,這樣就不用擔(dān)心影響到其他切片中的數(shù)據(jù)。
6.內(nèi)置 copy 函數(shù) func copy(dst, src []T) int
copy 函數(shù)不會(huì)因?yàn)樵衅湍繕?biāo)切片的長度問題而額外分配底層數(shù)組的內(nèi)存,它只負(fù)責(zé)拷貝數(shù)組的內(nèi)容蛤袒,從原切片拷貝到目標(biāo)切片熄云,拷貝的量是原切片和目標(biāo)切片長度的較小值 —— min(len(src), len(dst)),函數(shù)返回的是拷貝的實(shí)際長度妙真。

func main() {
 var s = make([]int, 5, 8)
 for i:=0;i<len(s);i++ {
  s[i] = i+1
 }
 fmt.Println(s)
 var d = make([]int, 2, 6)
 var n = copy(d, s)
 fmt.Println(n, d)
}
-----------
[1 2 3 4 5]
2 [1 2]

7.range遍歷
需要強(qiáng)調(diào)的是缴允,range創(chuàng)建了每個(gè)元素的副本,而不是直接返回該元素的引用

// 創(chuàng)建一個(gè)整型切片
// 其長度和容量都是 4 個(gè)元素
slice := []int{10, 20, 30, 40}
// 迭代每個(gè)元素珍德,并顯示值和地址
for index, value := range slice {
fmt.Printf("Value: %d Value-Addr: %X ElemAddr: %X\n",
value, &value, &slice[index])
}
Output:
Value: 10 Value-Addr: 10500168 ElemAddr: 1052E100
Value: 20 Value-Addr: 10500168 ElemAddr: 1052E104
Value: 30 Value-Addr: 10500168 ElemAddr: 1052E108
Value: 40 Value-Addr: 10500168 ElemAddr: 1052E10C

因?yàn)榈祷氐淖兞渴且粋€(gè)迭代過程中根據(jù)切片依次賦值的新變量练般,所以 value 的地址總是相同的。要想獲取每個(gè)元素的地址锈候,可以使用切片變量和索引值薄料。

8.沒有push,pop這些功能
參考[譯]Go Slice 秘籍

Pop
x, a = a[len(a)-1], a[:len(a)-1]

Push
a = append(a, x)

Shift
x, a := a[0], a[1:]

Unshift
a = append([]T{x}, a...)

要?jiǎng)h除slice中間的某個(gè)元素并保存原有的元素順序,可以通過內(nèi)置的copy函數(shù)將后面的子slice向前依次移動(dòng)一位完成

func remove(slice []int, i int) []int {
copy(slice[i:], slice[i+1:])
return slice[:len(slice)-1]
}

參照上面的copy解釋泵琳,slice[i+1:]的長度必定是小于slice[i:]的都办,所以不會(huì)出現(xiàn)copy過程中丟失自己想留的數(shù)據(jù)。然后copy不改變?cè)械讓訑?shù)組的len和cap虑稼,只是把數(shù)據(jù)往前覆蓋了一個(gè)元素,所以必須使用return slice[:len(slice)-1]才是想要的結(jié)果势木。
9.可變參數(shù)

func sum(vals...int) int {
total := 0
for _, val := range vals {
total += val
}
return total
}

sum函數(shù)返回任意個(gè)int型參數(shù)的和蛛倦。在函數(shù)體中,vals被看作是類型為[] int的切片。sum可以接收任意數(shù)量的int型參數(shù):

fmt.Println(sum()) // "0"
fmt.Println(sum(3)) // "3"
fmt.Println(sum(1, 2, 3, 4)) // "10"

10.清空
參考 展示不同方式清空 slice 的效果

package main

import (
    "fmt"
)

func dump(letters []string) {
    fmt.Printf("addr = %p\n", letters)
    fmt.Println("letters = ", letters)
    fmt.Println(cap(letters))
    fmt.Println(len(letters))
    for i := range letters {
        fmt.Println(i, letters[i])
    }
}

func main() {
    fmt.Println("=== 基礎(chǔ)數(shù)據(jù) ==========")
    letters := []string{"a", "b", "c", "d"}
    dump(letters)

    fmt.Println("=== ====== ==========")

    fmt.Println("=== \"原地\"清空 ===")
    fmt.Println("=== 效果:")
    fmt.Println("=== 1.直接在原 slice 上操作啦桌,故無 GC 行為")
    fmt.Println("=== 2.清空后 cap 值和之前相同溯壶,len 值清零")
    letters = letters[:0]
    dump(letters)

    fmt.Println("=== 添加元素效果:基于原 slice 操作,故再未超 cap 前無需內(nèi)存分配")
    letters = append(letters, "e")
    dump(letters)


    fmt.Println("=== ====== ==========")
    fmt.Println("=== 基于 nil 清空 ===")
    fmt.Println("=== 效果:")
    fmt.Println("=== 1.類似 C 語言中賦值空指針甫男,原內(nèi)容會(huì)被 GC 處理")
    fmt.Println("=== 2.清空后 cap 值清零且改,len 值清零")
    letters = nil
    dump(letters)

    fmt.Println("=== 添加元素效果:類似從無到有創(chuàng)建 slice")
    letters = append(letters, "e")
    dump(letters)
}

運(yùn)行結(jié)果

=== 基礎(chǔ)數(shù)據(jù) ==========
addr = 0xc420070080
letters =  [a b c d]
4
4
0 a
1 b
2 c
3 d
=== ====== ==========
=== "原地"清空 ===
=== 效果:
=== 1.直接在原 slice 上操作,故無 GC 行為
=== 2.清空后 cap 值和之前相同板驳,len 值清零
addr = 0xc420070080
letters =  []
4
0
=== 添加元素效果:基于原 slice 操作又跛,故再未超 cap 前無需內(nèi)存分配
addr = 0xc420070080
letters =  [e]
4
1
0 e
=== ====== ==========
=== 基于 nil 清空 ===
=== 效果:
=== 1.類似 C 語言中賦值空指針,原內(nèi)容會(huì)被 GC 處理
=== 2.清空后 cap 值清零若治,len 值清零
addr = 0x0
letters =  []
0
0
=== 添加元素效果:類似從無到有創(chuàng)建 slice
addr = 0xc42007c270
letters =  [e]
1
1
0 e
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末慨蓝,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子端幼,更是在濱河造成了極大的恐慌礼烈,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,997評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件婆跑,死亡現(xiàn)場離奇詭異此熬,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,603評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門犀忱,熙熙樓的掌柜王于貴愁眉苦臉地迎上來募谎,“玉大人,你說我怎么就攤上這事峡碉〗矗” “怎么了?”我有些...
    開封第一講書人閱讀 163,359評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵鲫寄,是天一觀的道長吉执。 經(jīng)常有香客問我,道長地来,這世上最難降的妖魔是什么戳玫? 我笑而不...
    開封第一講書人閱讀 58,309評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮未斑,結(jié)果婚禮上咕宿,老公的妹妹穿的比我還像新娘。我一直安慰自己蜡秽,他們只是感情好府阀,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,346評(píng)論 6 390
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著芽突,像睡著了一般试浙。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上寞蚌,一...
    開封第一講書人閱讀 51,258評(píng)論 1 300
  • 那天田巴,我揣著相機(jī)與錄音,去河邊找鬼挟秤。 笑死壹哺,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的艘刚。 我是一名探鬼主播管宵,決...
    沈念sama閱讀 40,122評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼攀甚!你這毒婦竟也來了啄糙?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,970評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤云稚,失蹤者是張志新(化名)和其女友劉穎隧饼,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體静陈,經(jīng)...
    沈念sama閱讀 45,403評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡燕雁,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,596評(píng)論 3 334
  • 正文 我和宋清朗相戀三年诞丽,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片拐格。...
    茶點(diǎn)故事閱讀 39,769評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡僧免,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出捏浊,到底是詐尸還是另有隱情懂衩,我是刑警寧澤,帶...
    沈念sama閱讀 35,464評(píng)論 5 344
  • 正文 年R本政府宣布金踪,位于F島的核電站浊洞,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏胡岔。R本人自食惡果不足惜法希,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,075評(píng)論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望靶瘸。 院中可真熱鬧苫亦,春花似錦、人聲如沸怨咪。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,705評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽诗眨。三九已至饼丘,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間辽话,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,848評(píng)論 1 269
  • 我被黑心中介騙來泰國打工卫病, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留油啤,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,831評(píng)論 2 370
  • 正文 我出身青樓蟀苛,卻偏偏與公主長得像益咬,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子帜平,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,678評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 線性結(jié)構(gòu)是計(jì)算機(jī)最常用的數(shù)據(jù)結(jié)構(gòu)之一幽告。無論是數(shù)組(arrary)還是鏈表(list),在編程中不可或缺裆甩。golan...
    _二少爺閱讀 6,611評(píng)論 5 13
  • 1.安裝 https://studygolang.com/dl 2.使用vscode編輯器安裝go插件 3.go語...
    go含羞草閱讀 1,553評(píng)論 0 6
  • 出處---Go編程語言 歡迎來到 Go 編程語言指南冗锁。本指南涵蓋了該語言的大部分重要特性 Go 語言的交互式簡介,...
    Tuberose閱讀 18,426評(píng)論 1 46
  • 一入咳嗽坑叨叙,學(xué)問何其深锭弊。越查越多,越多越查擂错。最后味滞,我放棄了,不寫了钮呀,就簡單記錄下七妹子這次的積食咳嗽發(fā)熱好了剑鞍。 一...
    七嫲嫲閱讀 2,483評(píng)論 0 0
  • 我現(xiàn)在已經(jīng)陷于一種境地 一種悲劇的境地 或許不悲劇 我現(xiàn)在已經(jīng)開始看不懂自己寫了啥…… 是不是精分前兆?
    丁一文閱讀 111評(píng)論 1 2