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

Fork me on GitHub
隨筆 - 215  文章 - 13  trackbacks - 0
<2015年11月>
25262728293031
1234567
891011121314
15161718192021
22232425262728
293012345


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

常用鏈接

留言簿(1)

隨筆分類

隨筆檔案

相冊

Awesome

Blog

Book

GitHub

Link

搜索

  •  

積分與排名

  • 積分 - 220943
  • 排名 - 117

最新評論

閱讀排行榜

 

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

感謝作者:smallnest

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


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

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

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

這是Go語言中你理解后續問題的基礎。

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

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

副本的創建

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

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 passV(b Bird) {
b.Age++
b.Name = "Great" + b.Name
fmt.Printf("傳入修改后的Bird:\t %+v, \t內存地址:%p\n", b, &b)
}
func main() {
parrot := Bird{Age: 1, Name: "Blue"}
fmt.Printf("原始的Bird:\t\t %+v, \t\t內存地址:%p\n", parrot, &parrot)
passV(parrot)
fmt.Printf("調用后原始的Bird:\t %+v, \t\t內存地址:%p\n", parrot, &parrot)
}

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

1
2
3
原始的Bird: {Age:1 Name:Blue}, 內存地址:0xc420012260
傳入修改后的Bird: {Age:2 Name:GreatBlue}, 內存地址:0xc4200122c0
調用后原始的Bird: {Age:1 Name:Blue}, 內存地址:0xc420012260

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

*T的副本創建

修改上面的例子,將函數的參數類型由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內存地址:%p, 指針的內存地址: %p\n", *b, b, &b)
}
func main() {
parrot := &Bird{Age: 1, Name: "Blue"}
fmt.Printf("原始的Bird:\t\t %+v, \t\t內存地址:%p, 指針的內存地址: %p\n", *parrot, parrot, &parrot)
passP(parrot)
fmt.Printf("調用后原始的Bird:\t %+v, \t內存地址:%p, 指針的內存地址: %p\n", *parrot, parrot, &parrot)
}

運行后輸出結果:

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

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

當然,一位對Go有深入了解的讀者都已經對這個知識有所了解,也明白了T*T作為參數的時候副本創建的不同。

如何選擇 T*T

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

一般的判斷標準是看副本創建的成本和需求。

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

什么時候發生副本創建

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

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

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

最常見的賦值的例子是對變量的賦值,包括函數內和函數外:

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內存地址:%p\n", parrot1, &parrot1)
fmt.Printf("parrot2:\t\t %+v, \t\t內存地址:%p\n", parrot2, &parrot2)
parrot3 := parrot1
fmt.Printf("parrot2:\t\t %+v, \t\t內存地址:%p\n", parrot3, &parrot3)
parrot4 := Parrot(parrot1)
fmt.Printf("parrot4:\t\t %+v, \t\t內存地址:%p\n", parrot4, &parrot4)
}

輸出結果:

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

可以看到這幾個變量的內存地址都不相同,說明發生了賦值。

map、slice和數組

slice,map和數組在初始化和按索引設置的時候也會創建副本:

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內存地址:%p\n", parrot1, &parrot1)
//slice
s := []Bird{parrot1}
s = append(s, parrot1)
parrot1.Age = 3
fmt.Printf("parrot2:\t\t %+v, \t\t內存地址:%p\n", s[0], &(s[0]))
fmt.Printf("parrot3:\t\t %+v, \t\t內存地址:%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內存地址:%p\n", parrot5, &parrot5)
parrot1.Age = 1
//array
a := [2]Bird{parrot1}
parrot1.Age = 6
fmt.Printf("parrot6:\t\t %+v, \t\t內存地址:%p\n", a[0], &a[0])
parrot1.Age = 1
a[1] = parrot1
parrot1.Age = 7
fmt.Printf("parrot7:\t\t %+v, \t\t內存地址:%p\n", a[1], &a[1])
}

輸出結果

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

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

for-range循環

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

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內存地址:%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內存地址:%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內存地址:%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內存地址:%p\n", (i + 2), p, &p)
}
}

輸出結果

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

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

channel

往channel中send對象的時候也會創建對象的副本:

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內存地址:%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內存地址:%p\n", 2, p, &p)
p = <-ch
fmt.Printf("parrot%d:\t\t %+v, \t\t內存地址:%p\n", 3, p, &p)
p = <-ch
fmt.Printf("parrot%d:\t\t %+v, \t\t內存地址:%p\n", 4, p, &p)
}

輸出結果:

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

函數參數和返回值

將變量作為參數傳遞給函數和方法會發生副本的創建。
對于返回值,將返回值賦值給其它變量或者傳遞給其它的函數和方法,就會創建副本。

Method Receiver

因為方法(method)最終會產生一個receiver作為第一個參數的函數(參看規范),所以就比較好理解method receiver的副本創建的規則了。
當receiver為T類型時,會發生創建副本,調用副本上的方法。
當receiver為*T類型時,只是會創建對象的指針,不創建對象的副本,方法內對receiver的改動會影響原始值。

不同類型的副本創建

bool,數值和指針

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

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

數組

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

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內存地址:%p\n", a1, &a1)
a2 := a1
a1[0] = 4
a1[1] = 5
a1[2] = 6
fmt.Printf("a2:\t\t %+v, \t\t內存地址:%p\n", a2, &a2)
}

輸出

1
2
a1: [1 2 3], 內存地址:0xc420012260
a2: [1 2 3], 內存地址:0xc4200122c0

對于[...]T[...]*T的區別,我想你也應該清楚了,[...]*T創建的副本的元素時元數組元素指針的副本。

map、slice 和 channel

網上一般說, 這三種類型都是指向指針類型,指向一個底層的數據結構。
因此呢,在定義類型的時候就不必定義成*T了。

當然你可以這么認為,不過我認為這是不準確的,比如slice,其實你可以看成是SliceHeader對象,只不過它的數據Data是一個指針,所以它的副本的創建對性能的影響可以忽略。

字符串

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

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

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

函數

函數也是一個指針類型,對函數對象的賦值只是又創建了一個對次函數對象的指針。

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內存地址:%p\n", f1, &f1)
f2 := f1
fmt.Printf("f2:\t\t %+v, \t\t內存地址:%p\n", f2, &f2)
}

輸出結果:

1
2
f1: 0x2200, 內存地址:0xc420028020
f2: 0x2200, 內存地址: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>
            亚洲久久一区| 亚洲视屏一区| 欧美亚男人的天堂| 欧美另类videos死尸| 欧美国产视频在线| 欧美精品成人91久久久久久久| 欧美在线播放一区| 欧美专区18| 久久精品国产999大香线蕉| 欧美资源在线| 免费的成人av| 欧美+亚洲+精品+三区| 欧美精品九九| 国产精品成人播放| 国产一区91| 亚洲欧洲另类国产综合| 一区二区三区久久| 欧美一级黄色录像| 可以看av的网站久久看| 欧美激情二区三区| 亚洲无吗在线| 久久九九精品99国产精品| 美日韩精品免费观看视频| 欧美日韩蜜桃| 国产在线一区二区三区四区| 日韩一级精品| 久久精品国产96久久久香蕉| 欧美激情按摩在线| 中国女人久久久| 久久av二区| 欧美日韩美女| 亚洲国产精品成人久久综合一区| 一本色道**综合亚洲精品蜜桃冫| 久久久久久日产精品| 亚洲区免费影片| 亚洲已满18点击进入久久| 久久先锋影音av| 欧美小视频在线观看| 激情久久影院| 午夜影院日韩| 亚洲欧洲日韩在线| 久久久久久久999精品视频| 欧美日韩精品在线观看| 伊人夜夜躁av伊人久久| 亚洲综合色网站| 亚洲国产精品ⅴa在线观看| 欧美一区午夜精品| 国产精品草莓在线免费观看| 亚洲国产欧美久久| 久久精品国产亚洲精品| 亚洲精品久久7777| 玖玖在线精品| 欧美在线日韩精品| 国产精品成人免费视频| 亚洲素人在线| 91久久久久| 欧美黄污视频| 亚洲激情在线| 欧美成人午夜剧场免费观看| 欧美影院一区| 韩国欧美国产1区| 欧美专区18| 亚洲综合第一| 国产精品swag| 午夜精品福利在线| 亚洲视频精选| 国产精品视频最多的网站| 亚洲神马久久| 亚洲午夜久久久| 国产精品久久久久久模特| 亚洲一区3d动漫同人无遮挡| 亚洲卡通欧美制服中文| 欧美日韩国产亚洲一区 | 国产综合视频在线观看| 欧美一区激情| 欧美中文日韩| 亚洲国产综合在线看不卡| 欧美国产高清| 欧美日韩成人免费| 午夜精品在线| 久久精品欧美日韩精品| 亚洲国产视频一区二区| 亚洲精品美女久久7777777| 欧美三级中文字幕在线观看| 亚洲手机在线| 欧美在线国产精品| 亚洲福利在线视频| 亚洲精品在线观看免费| 欧美性猛片xxxx免费看久爱| 香蕉久久一区二区不卡无毒影院 | 国产亚洲人成a一在线v站 | 夜夜嗨av一区二区三区网站四季av| 欧美人成在线| 亚洲欧美日韩第一区| 亚洲综合大片69999| 亚洲国产精品女人久久久| 欧美成人dvd在线视频| 欧美日本三区| 久久男人资源视频| 欧美成人综合| 亚洲欧美视频在线观看视频| 久久久午夜视频| 亚洲免费一在线| 久久国产精品一区二区| 一区二区激情| 亚洲国产成人不卡| 国产精品三级视频| 欧美aaa级| 国产精品一页| 欧美黄色视屏| 国产伦理一区| 99国产精品久久| 亚洲欧洲日韩女同| 午夜日韩在线| 亚洲视频日本| 老司机久久99久久精品播放免费| 亚洲女人av| 欧美福利视频在线| 久久夜色精品亚洲噜噜国产mv | 另类人畜视频在线| 国产精品久久久999| 亚洲电影免费在线观看| 国产综合色一区二区三区| 99在线精品免费视频九九视| 激情成人综合| 性做久久久久久久久| 一本久久综合亚洲鲁鲁| 久久综合色88| 老司机午夜精品视频| 国产精品毛片一区二区三区| 亚洲国产精品电影| 亚洲激情视频| 久久久欧美一区二区| 久久大香伊蕉在人线观看热2| 欧美日本中文字幕| 你懂的一区二区| 韩国美女久久| 久久精品国产在热久久| 欧美一区综合| 国产日韩欧美一区二区| 午夜一区不卡| 久热精品视频| 国语精品中文字幕| 欧美中文在线观看国产| 久久久久久久久岛国免费| 韩国成人精品a∨在线观看| 欧美一站二站| 免费视频亚洲| 亚洲国产日韩欧美在线图片| 久久人人爽爽爽人久久久| 久久综合给合| 91久久精品一区| 欧美另类一区二区三区| 亚洲欧洲日夜超级视频| 亚洲一区免费在线观看| 国产精品久久久| 性18欧美另类| 免费久久99精品国产自在现线| 在线播放一区| 欧美日韩高清免费| 亚洲作爱视频| 久久精品系列| 亚洲黄色免费| 国产精品久久久对白| 亚洲亚洲精品三区日韩精品在线视频 | 狂野欧美激情性xxxx| 亚洲国产综合在线| 欧美日韩在线电影| 亚洲欧美精品在线| 国产精品久久久久久久久久久久久久 | 免费成人你懂的| 日韩视频一区二区三区在线播放免费观看 | 亚洲自拍另类| 免费成人av在线| 夜夜爽夜夜爽精品视频| 国产精品美女久久久久久2018| 欧美伊久线香蕉线新在线| 亚洲国产精品久久久| 中文在线资源观看网站视频免费不卡| 国产精品三上| 欧美成人一二三| 亚洲影视在线播放| 免费成人av| 亚洲午夜在线观看视频在线| 国产亚洲精品7777| 欧美日韩免费区域视频在线观看| 久久亚洲视频| 亚洲综合电影一区二区三区| 韩国免费一区| 欧美午夜在线观看| 久久亚洲精品一区二区| 亚洲综合视频1区| 亚洲人成网站在线播| 久久国产精品久久w女人spa| 亚洲电影免费观看高清完整版在线| 欧美天堂亚洲电影院在线观看| 久久国产精品久久国产精品| 一区二区三区欧美| 欧美不卡一卡二卡免费版| 亚洲一品av免费观看|