青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

Fork me on GitHub
隨筆 - 215  文章 - 13  trackbacks - 0
<2017年11月>
2930311234
567891011
12131415161718
19202122232425
262728293012
3456789


專注即時通訊及網(wǎng)游服務(wù)端編程
------------------------------------
Openresty 官方模塊
Openresty 標(biāo)準(zhǔn)模塊(Opm)
Openresty 三方模塊
------------------------------------
本博收藏大部分文章為轉(zhuǎn)載,并在文章開頭給出了原文出處,如有再轉(zhuǎn),敬請保留相關(guān)信息,這是大家對原創(chuàng)作者勞動成果的自覺尊重!!如為您帶來不便,請于本博下留言,謝謝配合。

常用鏈接

留言簿(1)

隨筆分類

隨筆檔案

相冊

Awesome

Blog

Book

GitHub

Link

搜索

  •  

積分與排名

  • 積分 - 220944
  • 排名 - 117

最新評論

閱讀排行榜

 

http://studygolang.com/articles/9357
本文來自:鳥窩

感謝作者:smallnest

查看原文:[]T 還是 []*T, 這是一個問題 全面分析Go語言中的類型和類型指針的抉擇


在編程語言深入討論中,經(jīng)常被大家提起也是爭論最多的討論之一就是按值(by value)還是按引用傳遞(by reference, by pointer),你可以在C/C++或者Java的社區(qū)經(jīng)常看到這樣的討論,也會看到很多這樣的面試題。

對于Go語言,嚴格意義上來講,只有一種傳遞,也就是按值傳遞(by value)。當(dāng)一個變量當(dāng)作參數(shù)傳遞的時候,會創(chuàng)建一個變量的副本,然后傳遞給函數(shù)或者方法,你可以看到這個副本的地址和變量的地址是不一樣的。

當(dāng)變量當(dāng)做指針被傳遞的時候,一個新的指針被創(chuàng)建,它指向變量指向的同樣的內(nèi)存地址,所以你可以將這個指針看成原始變量指針的副本。當(dāng)這樣理解的時候,我們就可以理解成Go總是創(chuàng)建一個副本按值轉(zhuǎn)遞,只不過這個副本有時候是變量的副本,有時候是變量指針的副本。

這是Go語言中你理解后續(xù)問題的基礎(chǔ)。

但是Go語言的情況比較復(fù)雜,我們什么時候選擇 T 作為參數(shù)類型,什么時候選擇 *T作為參數(shù)類型? []T是傳遞的指針還是值?選擇[]T還是[]*T? 哪些類型復(fù)制和傳遞的時候會創(chuàng)建副本?什么情況下會發(fā)生副本創(chuàng)建?

本文將詳細介紹Go語言的變量的副本創(chuàng)建還是變量指針的副本創(chuàng)建的case以及各種類型在這些case的情況。

副本的創(chuàng)建

前面已經(jīng)講到,T類型的變量和*T類型的變量在當(dāng)做函數(shù)或者方法的參數(shù)時會傳遞它的副本。我們先看看例子。

T的副本創(chuàng)建

首先看一下 參數(shù)類型為T的函數(shù)調(diào)用的情況:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package main
import "fmt"
type Bird struct {
Age int
Name string
}
func passV(b Bird) {
b.Age++
b.Name = "Great" + b.Name
fmt.Printf("傳入修改后的Bird:\t %+v, \t內(nèi)存地址:%p\n", b, &b)
}
func main() {
parrot := Bird{Age: 1, Name: "Blue"}
fmt.Printf("原始的Bird:\t\t %+v, \t\t內(nèi)存地址:%p\n", parrot, &parrot)
passV(parrot)
fmt.Printf("調(diào)用后原始的Bird:\t %+v, \t\t內(nèi)存地址:%p\n", parrot, &parrot)
}

運行后輸入結(jié)果(每次運行指針的值可能不同):

1
2
3
原始的Bird: {Age:1 Name:Blue}, 內(nèi)存地址:0xc420012260
傳入修改后的Bird: {Age:2 Name:GreatBlue}, 內(nèi)存地址:0xc4200122c0
調(diào)用后原始的Bird: {Age:1 Name:Blue}, 內(nèi)存地址:0xc420012260

可以看到,在T類型作為參數(shù)的時候,傳遞的參數(shù)parrot會將它的副本(內(nèi)存地址0xc4200122c0)傳遞給函數(shù)passV,在這個函數(shù)內(nèi)對參數(shù)的改變不會影響原始的對象。

*T的副本創(chuàng)建

修改上面的例子,將函數(shù)的參數(shù)類型由T改為*T:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package main
import "fmt"
type Bird struct {
Age int
Name string
}
func passP(b *Bird) {
b.Age++
b.Name = "Great" + b.Name
fmt.Printf("傳入修改后的Bird:\t %+v, \t內(nèi)存地址:%p, 指針的內(nèi)存地址: %p\n", *b, b, &b)
}
func main() {
parrot := &Bird{Age: 1, Name: "Blue"}
fmt.Printf("原始的Bird:\t\t %+v, \t\t內(nèi)存地址:%p, 指針的內(nèi)存地址: %p\n", *parrot, parrot, &parrot)
passP(parrot)
fmt.Printf("調(diào)用后原始的Bird:\t %+v, \t內(nèi)存地址:%p, 指針的內(nèi)存地址: %p\n", *parrot, parrot, &parrot)
}

運行后輸出結(jié)果:

1
2
3
原始的Bird: {Age:1 Name:Blue}, 內(nèi)存地址:0xc420076000, 指針的內(nèi)存地址: 0xc420074000
傳入修改后的Bird: {Age:2 Name:GreatBlue}, 內(nèi)存地址:0xc420076000, 指針的內(nèi)存地址: 0xc420074010
調(diào)用后原始的Bird: {Age:2 Name:GreatBlue}, 內(nèi)存地址:0xc420076000, 指針的內(nèi)存地址: 0xc420074000

可以看到在函數(shù)passP中,參數(shù)p是一個指向Bird的指針,傳遞參數(shù)給它的時候會創(chuàng)建指針的副本(0xc420074010),只不過指針0xc4200740000xc420074010都指向內(nèi)存地址0xc420076000。 函數(shù)內(nèi)對*T的改變顯然會影響原始的對象,因為它是對同一個對象的操作。

當(dāng)然,一位對Go有深入了解的讀者都已經(jīng)對這個知識有所了解,也明白了T*T作為參數(shù)的時候副本創(chuàng)建的不同。

如何選擇 T*T

在定義函數(shù)和方法的時候,作為一位資深的Go開發(fā)人員,一定會對函數(shù)的參數(shù)和返回值定義成T*T深思熟慮,有些情況下可能還會有些苦惱。
那么什么時候才應(yīng)該把參數(shù)定義成類型T,什么情況下定義成類型*T呢。

一般的判斷標(biāo)準(zhǔn)是看副本創(chuàng)建的成本和需求。

  1. 不想變量被修改。 如果你不想變量被函數(shù)和方法所修改,那么選擇類型T。相反,如果想修改原始的變量,則選擇*T
  2. 如果變量是一個的struct或者數(shù)組,則副本的創(chuàng)建相對會影響性能,這個時候考慮使用*T,只創(chuàng)建新的指針,這個區(qū)別是巨大的
  3. (不針對函數(shù)參數(shù),只針對本地變量/本地變量)對于函數(shù)作用域內(nèi)的參數(shù),如果定義成T,Go編譯器盡量將對象分配到棧上,而*T很可能會分配到對象上,這對垃圾回收會有影響

什么時候發(fā)生副本創(chuàng)建

上面舉的例子都是作為函數(shù)參數(shù)時發(fā)生的副本的創(chuàng)建,還有很多情況下會發(fā)生副本的創(chuàng)建,甚至有些“隱蔽”的情況。
編程的時候如何小心這些情況呢,一條原則就是:

A go assignment is a copy of the value itself
賦值的時候就會創(chuàng)建對象副本

Assignment的語法表達式如下:

Assignment = ExpressionList assign_op ExpressionList .
assign_op = [ add_op | mul_op ] "=" .

Each left-hand side operand must be addressable, a map index expression, or (for = assignments only) the blank identifier. Operands may be parenthesized.

最常見的case

最常見的賦值的例子是對變量的賦值,包括函數(shù)內(nèi)和函數(shù)外:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package main
import "fmt"
type Bird struct {
Age int
Name string
}
type Parrot struct {
Age int
Name string
}
var parrot1 = Bird{Age: 1, Name: "Blue"}
var parrot2 = parrot1
func main() {
fmt.Printf("parrot1:\t\t %+v, \t\t內(nèi)存地址:%p\n", parrot1, &parrot1)
fmt.Printf("parrot2:\t\t %+v, \t\t內(nèi)存地址:%p\n", parrot2, &parrot2)
parrot3 := parrot1
fmt.Printf("parrot2:\t\t %+v, \t\t內(nèi)存地址:%p\n", parrot3, &parrot3)
parrot4 := Parrot(parrot1)
fmt.Printf("parrot4:\t\t %+v, \t\t內(nèi)存地址:%p\n", parrot4, &parrot4)
}

輸出結(jié)果:

1
2
3
4
parrot1: {Age:1 Name:Blue}, 內(nèi)存地址:0xfa0a0
parrot2: {Age:1 Name:Blue}, 內(nèi)存地址:0xfa0c0
parrot2: {Age:1 Name:Blue}, 內(nèi)存地址:0xc42007e0c0
parrot4: {Age:1 Name:Blue}, 內(nèi)存地址:0xc42007e100

可以看到這幾個變量的內(nèi)存地址都不相同,說明發(fā)生了賦值。

map、slice和數(shù)組

slice,map和數(shù)組在初始化和按索引設(shè)置的時候也會創(chuàng)建副本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package main
import "fmt"
type Bird struct {
Age int
Name string
}
var parrot1 = Bird{Age: 1, Name: "Blue"}
func main() {
fmt.Printf("parrot1:\t\t %+v, \t\t內(nèi)存地址:%p\n", parrot1, &parrot1)
//slice
s := []Bird{parrot1}
s = append(s, parrot1)
parrot1.Age = 3
fmt.Printf("parrot2:\t\t %+v, \t\t內(nèi)存地址:%p\n", s[0], &(s[0]))
fmt.Printf("parrot3:\t\t %+v, \t\t內(nèi)存地址:%p\n", s[1], &(s[1]))
parrot1.Age = 1
//map
m := make(map[int]Bird)
m[0] = parrot1
parrot1.Age = 4
fmt.Printf("parrot4:\t\t %+v\n", m[0])
parrot1.Age = 5
parrot5 := m[0]
fmt.Printf("parrot5:\t\t %+v, \t\t內(nèi)存地址:%p\n", parrot5, &parrot5)
parrot1.Age = 1
//array
a := [2]Bird{parrot1}
parrot1.Age = 6
fmt.Printf("parrot6:\t\t %+v, \t\t內(nèi)存地址:%p\n", a[0], &a[0])
parrot1.Age = 1
a[1] = parrot1
parrot1.Age = 7
fmt.Printf("parrot7:\t\t %+v, \t\t內(nèi)存地址:%p\n", a[1], &a[1])
}

輸出結(jié)果

1
2
3
4
5
6
7
parrot1: {Age:1 Name:Blue}, 內(nèi)存地址:0xfa0a0
parrot2: {Age:1 Name:Blue}, 內(nèi)存地址:0xc4200160f0
parrot3: {Age:1 Name:Blue}, 內(nèi)存地址:0xc420016108
parrot4: {Age:1 Name:Blue}
parrot5: {Age:1 Name:Blue}, 內(nèi)存地址:0xc420012320
parrot6: {Age:1 Name:Blue}, 內(nèi)存地址:0xc420016120
parrot7: {Age:1 Name:Blue}, 內(nèi)存地址:0xc420016138

可以看到 slice/map/數(shù)組 的元素全是原始變量的副本, 副本

for-range循環(huán)

for-range循環(huán)也是將元素的副本賦值給循環(huán)變量,所以變量得到的是集合元素的副本。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
package main
import "fmt"
type Bird struct {
Age int
Name string
}
var parrot1 = Bird{Age: 1, Name: "Blue"}
func main() {
fmt.Printf("parrot1:\t\t %+v, \t\t內(nèi)存地址:%p\n", parrot1, &parrot1)
//slice
s := []Bird{parrot1, parrot1, parrot1}
s[0].Age = 1
s[1].Age = 2
s[2].Age = 3
parrot1.Age = 4
for i, p := range s {
fmt.Printf("parrot%d:\t\t %+v, \t\t內(nèi)存地址:%p\n", (i + 2), p, &p)
}
parrot1.Age = 1
//map
m := make(map[int]Bird)
parrot1.Age = 1
m[0] = parrot1
parrot1.Age = 2
m[1] = parrot1
parrot1.Age = 3
m[2] = parrot1
parrot1.Age = 4
for k, v := range m {
fmt.Printf("parrot%d:\t\t %+v, \t\t內(nèi)存地址:%p\n", (k + 2), v, &v)
}
parrot1.Age = 4
//array
a := [...]Bird{parrot1, parrot1, parrot1}
a[0].Age = 1
a[1].Age = 2
a[2].Age = 3
parrot1.Age = 4
for i, p := range a {
fmt.Printf("parrot%d:\t\t %+v, \t\t內(nèi)存地址:%p\n", (i + 2), p, &p)
}
}

輸出結(jié)果

1
2
3
4
5
6
7
8
9
10
parrot1: {Age:1 Name:Blue}, 內(nèi)存地址:0xfb0a0
parrot2: {Age:1 Name:Blue}, 內(nèi)存地址:0xc4200122a0
parrot3: {Age:2 Name:Blue}, 內(nèi)存地址:0xc4200122a0
parrot4: {Age:3 Name:Blue}, 內(nèi)存地址:0xc4200122a0
parrot2: {Age:1 Name:Blue}, 內(nèi)存地址:0xc420012320
parrot3: {Age:2 Name:Blue}, 內(nèi)存地址:0xc420012320
parrot4: {Age:3 Name:Blue}, 內(nèi)存地址:0xc420012320
parrot2: {Age:1 Name:Blue}, 內(nèi)存地址:0xc4200123a0
parrot3: {Age:2 Name:Blue}, 內(nèi)存地址:0xc4200123a0
parrot4: {Age:3 Name:Blue}, 內(nèi)存地址:0xc4200123a0

注意循環(huán)變量是重用的,所以你看到它們的地址是相同的。

channel

往channel中send對象的時候也會創(chuàng)建對象的副本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package main
import "fmt"
type Bird struct {
Age int
Name string
}
var parrot1 = Bird{Age: 1, Name: "Blue"}
func main() {
ch := make(chan Bird, 3)
fmt.Printf("parrot1:\t\t %+v, \t\t內(nèi)存地址:%p\n", parrot1, &parrot1)
ch <- parrot1
parrot1.Age = 2
ch <- parrot1
parrot1.Age = 3
ch <- parrot1
parrot1.Age = 4
p := <-ch
fmt.Printf("parrot%d:\t\t %+v, \t\t內(nèi)存地址:%p\n", 2, p, &p)
p = <-ch
fmt.Printf("parrot%d:\t\t %+v, \t\t內(nèi)存地址:%p\n", 3, p, &p)
p = <-ch
fmt.Printf("parrot%d:\t\t %+v, \t\t內(nèi)存地址:%p\n", 4, p, &p)
}

輸出結(jié)果:

1
2
3
4
parrot1: {Age:1 Name:Blue}, 內(nèi)存地址:0xfa0a0
parrot2: {Age:1 Name:Blue}, 內(nèi)存地址:0xc4200122a0
parrot3: {Age:2 Name:Blue}, 內(nèi)存地址:0xc4200122a0
parrot4: {Age:3 Name:Blue}, 內(nèi)存地址:0xc4200122a0

函數(shù)參數(shù)和返回值

將變量作為參數(shù)傳遞給函數(shù)和方法會發(fā)生副本的創(chuàng)建。
對于返回值,將返回值賦值給其它變量或者傳遞給其它的函數(shù)和方法,就會創(chuàng)建副本。

Method Receiver

因為方法(method)最終會產(chǎn)生一個receiver作為第一個參數(shù)的函數(shù)(參看規(guī)范),所以就比較好理解method receiver的副本創(chuàng)建的規(guī)則了。
當(dāng)receiver為T類型時,會發(fā)生創(chuàng)建副本,調(diào)用副本上的方法。
當(dāng)receiver為*T類型時,只是會創(chuàng)建對象的指針,不創(chuàng)建對象的副本,方法內(nèi)對receiver的改動會影響原始值。

不同類型的副本創(chuàng)建

bool,數(shù)值和指針

bool和數(shù)值類型一般不必考慮指針類型,原因在于這些對象很小,創(chuàng)建副本的開銷可以忽略。只有你在想修改同一個變量的值的時候才考慮它們的指針。

指針類型就不用多說了,和數(shù)值類型類似。

數(shù)組

數(shù)組是值類型,賦值的時候會發(fā)生原始數(shù)組的復(fù)制,所以對于大的數(shù)組的參數(shù)傳遞和賦值,一定要慎重。

1
2
3
4
5
6
7
8
9
10
11
12
13
package main
import "fmt"
func main() {
a1 := [3]int{1, 2, 3}
fmt.Printf("a1:\t\t %+v, \t\t內(nèi)存地址:%p\n", a1, &a1)
a2 := a1
a1[0] = 4
a1[1] = 5
a1[2] = 6
fmt.Printf("a2:\t\t %+v, \t\t內(nèi)存地址:%p\n", a2, &a2)
}

輸出

1
2
a1: [1 2 3], 內(nèi)存地址:0xc420012260
a2: [1 2 3], 內(nèi)存地址:0xc4200122c0

對于[...]T[...]*T的區(qū)別,我想你也應(yīng)該清楚了,[...]*T創(chuàng)建的副本的元素時元數(shù)組元素指針的副本。

map、slice 和 channel

網(wǎng)上一般說, 這三種類型都是指向指針類型,指向一個底層的數(shù)據(jù)結(jié)構(gòu)。
因此呢,在定義類型的時候就不必定義成*T了。

當(dāng)然你可以這么認為,不過我認為這是不準(zhǔn)確的,比如slice,其實你可以看成是SliceHeader對象,只不過它的數(shù)據(jù)Data是一個指針,所以它的副本的創(chuàng)建對性能的影響可以忽略。

字符串

string類型類似slice,它等價StringHeader。所以很多情況下會用`unsafe.Pointer`與[]byte類型進行更有效的轉(zhuǎn)換,因為直接進行類型轉(zhuǎn)換string([]byte)會發(fā)生數(shù)據(jù)的復(fù)制。

字符串比較特殊,它的值不能修改,任何想對字符串的值做修改都會生成新的字符串。

大部分情況下你不需要定義成*string。唯一的例外你需要 nil值的時候。我們知道,類型string的空值/缺省值為"",但是如果你需要nil,你就必須定義*string。舉個例子,在對象序列化的時候""nil表示的意義是不一樣的,""表示字段存在,只不過字符串是空值,而nil表示字段不存在。

函數(shù)

函數(shù)也是一個指針類型,對函數(shù)對象的賦值只是又創(chuàng)建了一個對次函數(shù)對象的指針。

1
2
3
4
5
6
7
8
9
10
11
package main
import "fmt"
func main() {
f1 := func(i int) {}
fmt.Printf("f1:\t\t %+v, \t\t內(nèi)存地址:%p\n", f1, &f1)
f2 := f1
fmt.Printf("f2:\t\t %+v, \t\t內(nèi)存地址:%p\n", f2, &f2)
}

輸出結(jié)果:

1
2
f1: 0x2200, 內(nèi)存地址:0xc420028020
f2: 0x2200, 內(nèi)存地址:0xc420028030

參考文檔

  1. https://www.reddit.com/r/golang/comments/5lheyg/returning_t_vs_t/?
  2. https://github.com/google/go-github/issues/180
  3. http://openmymind.net/Things-I-Wish-Someone-Had-Told-Me-About-Go/
  4. http://goinbigdata.com/golang-pass-by-pointer-vs-pass-by-value/
  5. https://groups.google.com/forum/#!topic/golang-nuts/__BPVgK8LN0
  6. https://golang.org/ref/spec
  7. https://golang.org/doc/faq
  8. https://golang.org/doc/effective_go.html
  9. https://nathanleclaire.com/blog/2014/08/09/dont-get-bitten-by-pointer-vs-non-pointer-method-receivers-in-golang/
  10. https://dhdersch.github.io/golang/2016/01/23/golang-when-to-use-string-pointers.html
  11. https://dave.cheney.net/2016/03/19/should-methods-be-declared-on-t-or-t
  12. http://colobu.com/2016/10/28/When-are-function-parameters-passed-by-value/
posted on 2017-02-09 09:26 思月行云 閱讀(251) 評論(0)  編輯 收藏 引用 所屬分類: Golang
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            亚洲精品乱码久久久久久蜜桃91| 亚洲一区二区三区精品在线| 国产区精品在线观看| 欧美a一区二区| 噜噜噜噜噜久久久久久91| 欧美一站二站| 久久久久久久久久久成人| 久久综合九色综合欧美狠狠| 久久精品123| 蜜臀久久99精品久久久久久9 | 一区二区三区国产盗摄| 一区二区高清在线观看| 正在播放亚洲一区| 午夜免费久久久久| 蜜桃av久久久亚洲精品| 欧美日韩成人在线播放| 国产精品一区=区| 国产亚洲一级| 亚洲国产精品日韩| 亚洲一区二区欧美日韩| 久久九九热免费视频| 欧美激情中文不卡| 亚洲剧情一区二区| 午夜精品国产精品大乳美女| 久久综合色8888| 欧美视频你懂的| 伊人成人在线| 亚洲一区日本| 欧美激情四色 | 一区二区三区 在线观看视| 亚洲欧美网站| 欧美成人免费网站| 亚洲主播在线播放| 欧美激情一区二区| 国产综合久久久久久鬼色| 在线亚洲欧美视频| 久久亚洲春色中文字幕久久久| 欧美激情第8页| 欧美一区二区高清| 欧美午夜视频在线| 亚洲区在线播放| 久久久www成人免费精品| 国产精品vip| 欧美大胆成人| 黄色日韩网站视频| 午夜久久tv| 一本色道久久综合亚洲精品不 | 在线亚洲激情| 老牛国产精品一区的观看方式| 欧美性大战xxxxx久久久| 亚洲激情电影中文字幕| 久久久噜噜噜久久| 性做久久久久久| 国产嫩草一区二区三区在线观看 | 亚洲四色影视在线观看| 理论片一区二区在线| 激情久久久久| 久久久www| 久久爱www久久做| 国产视频久久久久| 久久久久久**毛片大全| 中日韩视频在线观看| 欧美激情偷拍| 亚洲精品日产精品乱码不卡| 欧美大胆成人| 欧美激情精品久久久六区热门 | 国产精品福利在线| 亚洲黄网站黄| 久久久久国产精品厨房| 99精品99久久久久久宅男| 久久久水蜜桃av免费网站| 欧美精品v日韩精品v国产精品| 国产精品国产三级国产a| 99精品国产在热久久| 免费欧美在线视频| 一区二区高清在线| 欧美日韩 国产精品| 亚洲国产欧美不卡在线观看| 亚洲欧美在线x视频| 亚洲福利视频一区二区| 欧美一区二区高清在线观看| 国产伦精品一区二区三区高清版 | 免费成人小视频| 午夜精品久久久久久久99樱桃| 欧美国产日韩一区二区| 亚洲第一精品福利| 欧美高清在线视频| 欧美日韩免费高清| 久久av二区| 欧美成人免费网| 久久成人免费电影| 日韩亚洲欧美高清| 亚洲性图久久| 亚洲欧美日韩成人高清在线一区| 国产在线精品自拍| 亚洲日本中文字幕| 欧美色精品在线视频| 久久久久久久久久码影片| 久久中文精品| 亚洲一区在线观看视频 | 欧美高清视频在线| 新狼窝色av性久久久久久| 久久国产免费看| 一本大道av伊人久久综合| 一区二区三区欧美亚洲| 午夜伦欧美伦电影理论片| 亚洲欧洲一区二区三区在线观看| 99国产精品视频免费观看一公开 | 国产亚洲电影| 亚洲国产欧美在线| 国产在线观看精品一区二区三区| 亚洲电影在线观看| 国产精品久久久久久久久搜平片| 免费在线成人| 国产欧美精品一区二区色综合 | 亚洲精品九九| 国产欧美日韩| 日韩一级精品| 亚洲精品日韩久久| 久久天天狠狠| 久久久久久穴| 国产日韩精品一区二区浪潮av| 亚洲精品国产精品国自产在线| 国产一区二区三区在线观看免费 | 亚洲国产精品激情在线观看 | 亚洲国产精品成人va在线观看| 亚洲午夜久久久| 亚洲精品女av网站| 久久免费99精品久久久久久| 欧美专区第一页| 国产精品一区二区久久久久| 日韩视频一区二区三区在线播放| 激情久久影院| 久久国产日韩| 久久婷婷综合激情| 国产一区二区中文| 欧美淫片网站| 久久久精品一区| 国内精品久久久久久影视8| 午夜一区二区三视频在线观看| 亚洲欧美经典视频| 欧美日韩一区二区三| 99在线精品观看| 亚洲视频在线二区| 欧美日韩亚洲一区二区三区| 亚洲国产综合91精品麻豆| 亚洲二区在线视频| 最新国产成人在线观看| 免费不卡在线视频| 韩国在线视频一区| 久久久久久久久久久久久久一区| 久久综合伊人77777麻豆| 黑人一区二区三区四区五区| 午夜影院日韩| 久久中文字幕一区| 怡红院精品视频| 欧美国产激情二区三区| 99re视频这里只有精品| 先锋影音久久久| 一区二区亚洲| 欧美精品一区二区久久婷婷| 欧美顶级大胆免费视频| 亚洲三级国产| 国产精品国产三级国产专区53| 亚洲制服欧美中文字幕中文字幕| 久久精品官网| 日韩一级在线| 国产精品一区在线播放| 久久精品国产999大香线蕉| 亚洲国产99| 亚洲午夜精品视频| 好看不卡的中文字幕| 欧美日韩国内| 欧美资源在线| 日韩午夜视频在线观看| 亚洲制服少妇| 亚洲国产精品久久久久秋霞不卡 | 久久超碰97中文字幕| 激情懂色av一区av二区av| 免费不卡在线视频| 一二三区精品| 欧美a级片网站| 亚洲欧美日韩综合aⅴ视频| 精品动漫3d一区二区三区免费版| 欧美精品激情在线| 久久激情婷婷| 亚洲午夜91| 亚洲高清123| 久久精品官网| 亚洲一区二区三区免费视频| 亚洲国产高清在线观看视频| 国产精品萝li| 欧美国产综合视频| 久久影院午夜论| 欧美伊久线香蕉线新在线| 99国产精品99久久久久久| 亚洲国产高清一区| 美腿丝袜亚洲色图| 久久精品国产一区二区电影| 中日韩高清电影网|