Swift:高級(jí)運(yùn)算符

中文文檔

一、位運(yùn)算符

位操作符通常在諸如圖像處理和創(chuàng)建設(shè)備驅(qū)動(dòng)等底層開發(fā)中使用,使用它可以單獨(dú)操作數(shù)據(jù)結(jié)構(gòu)中原始數(shù)據(jù)的比特位。在使用一個(gè)自定義的協(xié)議進(jìn)行通信的時(shí)候,運(yùn)用位運(yùn)算符來對(duì)原始數(shù)據(jù)進(jìn)行編碼和解碼也是非常有效的。

1、按位取反運(yùn)算符
  • ~: 按位取反運(yùn)算符, 對(duì)一個(gè)操作數(shù)的每一位都取反
按位取反運(yùn)算符
  • 這個(gè)運(yùn)算符是前置的,所以請(qǐng)不加任何空格地寫著操作數(shù)之前。
let initialBits: UInt8 = 0b00001111 
let invertedBits = ~initialBits  // 等于 0b11110000 
2、按位與運(yùn)算符
  • &: 按位與運(yùn)算符對(duì)兩個(gè)數(shù)進(jìn)行操作,然后返回一個(gè)新的數(shù),這個(gè)數(shù)的每個(gè)位都需要兩個(gè)輸入數(shù)的同一位都為1時(shí)才為1
按位與運(yùn)算符
  • 以下代碼,firstSixBits和lastSixBits中間4個(gè)位都為1。對(duì)它倆進(jìn)行按位與運(yùn)算后,就得到了00111100,即十進(jìn)制的60。
let firstSixBits: UInt8 = 0b11111100 
let lastSixBits: UInt8  = 0b00111111 
let middleFourBits = firstSixBits & lastSixBits  // 等于 00111100 
3、按位或運(yùn)算
  • |: 按位或運(yùn)算符, 比較兩個(gè)數(shù),然后返回一個(gè)新的數(shù),這個(gè)數(shù)的每一位設(shè)置1的條件是兩個(gè)輸入數(shù)的同一位都不為0(即任意一個(gè)為1,或都為1)。
按位或運(yùn)算
  • 如下代碼,someBits和moreBits在不同位上有1。按位或運(yùn)行的結(jié)果是11111110,即十進(jìn)制的254。
let someBits: UInt8 = 0b10110010 
let moreBits: UInt8 = 0b01011110 
let combinedbits = someBits | moreBits  // 等于 11111110 
4、按位異或運(yùn)算符
  • ^: 按位異或運(yùn)算符, 比較兩個(gè)數(shù),然后返回一個(gè)數(shù),這個(gè)數(shù)的每個(gè)位設(shè)為1的條件是兩個(gè)輸入數(shù)的同一位不同,如果相同就設(shè)為0。
按位異或運(yùn)算符
  • 以下代碼,firstBits和otherBits都有一個(gè)1跟另一個(gè)數(shù)不同的。所以按位異或的結(jié)果是把它這些位置為1,其他都置為0。
let firstBits: UInt8 = 0b00010100 
let otherBits: UInt8 = 0b00000101 
let outputBits = firstBits ^ otherBits  // 等于 00010001 
5、按位左移/右移運(yùn)算符
  • 左移運(yùn)算符<<和右移運(yùn)算符>>會(huì)把一個(gè)數(shù)的所有比特位按以下定義的規(guī)則向左或向右移動(dòng)指定位數(shù)。

  • 按位左移和按位右移的效果相當(dāng)把一個(gè)整數(shù)乘于或除于一個(gè)因子為2的整數(shù)。向左移動(dòng)一個(gè)整型的比特位相當(dāng)于把這個(gè)數(shù)乘于2,向右移一位就是除于2。

6、無符整型的移位操作
  • 對(duì)無符整型的移位的效果如下:
已經(jīng)存在的比特位向左或向右移動(dòng)指定的位數(shù)。
被移出整型存儲(chǔ)邊界的的位數(shù)直接拋棄,移動(dòng)留下的空白位用零0來填充。這種方法稱為邏輯移位。
  • 以下這張把展示了 11111111 << 1(11111111向左移1位),和 11111111 >> 1(11111111向右移1位)。藍(lán)色的是被移位的,灰色是被拋棄的,橙色的0是被填充進(jìn)來的
無符整型的移位操作
let shiftBits: UInt8 = 4   // 即二進(jìn)制的00000100 
shiftBits << 1             // 00001000 
shiftBits << 2             // 00010000 
shiftBits << 5             // 10000000 
shiftBits << 6             // 00000000 
shiftBits >> 2             // 00000001 
  • 你可以使用移位操作進(jìn)行其他數(shù)據(jù)類型的編碼和解碼。
let pink: UInt32 = 0xCC6699 
let redComponent = (pink & 0xFF0000) >> 16    // redComponent 是 0xCC, 即 204 
let greenComponent = (pink & 0x00FF00) >> 8   // greenComponent 是 0x66, 即 102 
let blueComponent = pink & 0x0000FF           // blueComponent 是 0x99, 即 153 
  • 這個(gè)例子使用了一個(gè)UInt32的命名為pink的常量來存儲(chǔ)層疊樣式表CSS中粉色的顏色值,CSS顏色#CC6699在Swift用十六進(jìn)制0xCC6699來表示。然后使用按位與(&)和按位右移就可以從這個(gè)顏色值中解析出紅(CC),綠(66),藍(lán)(99)三個(gè)部分。

  • 對(duì)0xCC6699和0xFF0000進(jìn)行按位與&操作就可以得到紅色部分。0xFF0000中的0了遮蓋了OxCC6699的第二和第三個(gè)字節(jié),這樣6699被忽略了,只留下0xCC0000。

  • 然后,按向右移動(dòng)16位,即 >> 16。十六進(jìn)制中每?jī)蓚€(gè)字符是8比特位,所以移動(dòng)16位的結(jié)果是把0xCC0000變成0x0000CC。這和0xCC是相等的,都是十進(jìn)制的204。

  • 同樣的,綠色部分來自于0xCC6699和0x00FF00的按位操作得到0x006600。然后向右移動(dòng)8們,得到0x66,即十進(jìn)制的102。

  • 最后,藍(lán)色部分對(duì)0xCC6699和0x0000FF進(jìn)行按位與運(yùn)算,得到0x000099,無需向右移位了,所以結(jié)果就是0x99,即十進(jìn)制的153。

7、有符整型的移位操作
  • 有符整型的移位操作相對(duì)復(fù)雜得多,因?yàn)檎?fù)號(hào)也是用二進(jìn)制位表示的
  • 有符整型通過第1個(gè)比特位(稱為符號(hào)位)來表達(dá)這個(gè)整數(shù)是正數(shù)還是負(fù)數(shù)。0代表正數(shù),1代表負(fù)數(shù)。
  • 其余的比特位(稱為數(shù)值位)存儲(chǔ)其實(shí)值。有符正整數(shù)和無符正整數(shù)在計(jì)算機(jī)里的存儲(chǔ)結(jié)果是一樣的,下來我們來看+4內(nèi)部的二進(jìn)制結(jié)構(gòu)。
  • 符號(hào)位為0,代表正數(shù),另外7比特位二進(jìn)制表示的實(shí)際值就剛好是4。
  • 負(fù)數(shù)呢,跟正數(shù)不同。負(fù)數(shù)存儲(chǔ)的是2n次方減去它的絕對(duì)值,n為數(shù)值位的位數(shù)。一個(gè)8比特的數(shù)有7個(gè)數(shù)值位,所以是27次方,即128
  • 我們來看-4存儲(chǔ)的二進(jìn)制結(jié)構(gòu)。
  • 現(xiàn)在符號(hào)位為1,代表負(fù)數(shù),7個(gè)數(shù)值位要表達(dá)的二進(jìn)制值是124,即128 - 4。
  • 負(fù)數(shù)的編碼方式稱為二進(jìn)制補(bǔ)碼表示。這種表示方式看起來很奇怪,但它有幾個(gè)優(yōu)點(diǎn)。

  • 首先,只需要對(duì)全部8個(gè)比特位(包括符號(hào))做標(biāo)準(zhǔn)的二進(jìn)制加法就可以完成 -1 + -4 的操作,忽略加法過程產(chǎn)生的超過8個(gè)比特位表達(dá)的任何信息。

  • 第二,由于使用二進(jìn)制補(bǔ)碼表示,我們可以和正數(shù)一樣對(duì)負(fù)數(shù)進(jìn)行按位左移右移的,同樣也是左移1位時(shí)乘于2,右移1位時(shí)除于2。要達(dá)到此目的,對(duì)有符整型的右移有一個(gè)特別的要求:
對(duì)有符整型按位右移時(shí),使用符號(hào)位(正數(shù)為0,負(fù)數(shù)為1)填充空白位。
  • 這就確保了在右移的過程中,有符整型的符號(hào)不會(huì)發(fā)生變化。這稱為算術(shù)移位。

  • 正因?yàn)檎龜?shù)和負(fù)數(shù)特殊的存儲(chǔ)方式,向右移位使它接近于0。移位過程中保持符號(hào)會(huì)不變,負(fù)數(shù)在接近0的過程中一直是負(fù)數(shù)。

二、溢出運(yùn)算符

  • 默認(rèn)情況下,當(dāng)你往一個(gè)整型常量或變量賦于一個(gè)它不能承載的大數(shù)時(shí),Swift不會(huì)讓你這么干的,它會(huì)報(bào)錯(cuò)。這樣,在操作過大或過小的數(shù)的時(shí)候就很安全了。
var potentialOverflow = Int16.max 
// potentialOverflow 等于 32767, 這是 Int16 能承載的最大整數(shù) 
potentialOverflow += 1 
// 噢, 出錯(cuò)了 
  • 當(dāng)然,你有意在溢出時(shí)對(duì)有效位進(jìn)行截?cái)啵憧刹捎靡绯鲞\(yùn)算,而非錯(cuò)誤處理。Swfit為整型計(jì)算提供了5個(gè)&符號(hào)開頭的溢出運(yùn)算符。
溢出加法 &+
溢出減法 &-
溢出乘法 &*
溢出除法 &/
溢出求余 &%
1、值的上溢出
  • 下面例子使用了溢出加法&+來解剖的無符整數(shù)的上溢出
var willOverflow = UInt8.max 
// willOverflow 等于UInt8的最大整數(shù) 255 
willOverflow = willOverflow &+ 1 
// 這時(shí)候 willOverflow 等于 0 
  • willOverflow用Int8所能承載的最大值255(二進(jìn)制11111111),然后用&+加1。然后UInt8就無法表達(dá)這個(gè)新值的二進(jìn)制了,也就導(dǎo)致了這個(gè)新值上溢出了,大家可以看下圖。溢出后,新值在UInt8的承載范圍內(nèi)的那部分是00000000,也就是0。
2、值的下溢出
  • 數(shù)值也有可能因?yàn)樘《浇纭Ee個(gè)例子:
  • UInt8的最小值是0(二進(jìn)制為00000000)。使用&-進(jìn)行溢出減1,就會(huì)得到二進(jìn)制的11111111即十進(jìn)制的255。
  • Swift代碼是這樣的:
var willUnderflow = UInt8.min 
// willUnderflow 等于UInt8的最小值0 
willUnderflow = willUnderflow &- 1 
// 此時(shí) willUnderflow 等于 255 
  • 有符整型也有類似的下溢出,有符整型所有的減法也都是對(duì)包括在符號(hào)位在內(nèi)的二進(jìn)制數(shù)進(jìn)行二進(jìn)制減法的,這在 "按位左移/右移運(yùn)算符" 一節(jié)提到過。最小的有符整數(shù)是-128,即二進(jìn)制的10000000。用溢出減法減去去1后,變成了01111111,即UInt8所能承載的最大整數(shù)127。
  • 對(duì)應(yīng)Swift代碼
var signedUnderflow = Int8.min 
// signedUnderflow 等于最小的有符整數(shù) -128 
signedUnderflow = signedUnderflow &- 1 
// 如今 signedUnderflow 等于 127 
3、除零溢出
  • 一個(gè)數(shù)除于0 i / 0,或者對(duì)0求余數(shù) i % 0,就會(huì)產(chǎn)生一個(gè)錯(cuò)誤。
let x = 1 
let y = x / 0 
  • 使用它們對(duì)應(yīng)的可溢出的版本的運(yùn)算符&/&%進(jìn)行除0操作時(shí)就會(huì)得到0值。
let x = 1 
let y = x &/ 0 
// y 等于 0 

三、優(yōu)先級(jí)和結(jié)合性

  • 與數(shù)學(xué)中的優(yōu)先級(jí)和結(jié)合性相同

四、運(yùn)算符函數(shù)

  • 讓已有的運(yùn)算符也可以對(duì)自定義的類和結(jié)構(gòu)進(jìn)行運(yùn)算,這稱為運(yùn)算符重載。

  • 例子中定義了一個(gè)名為Vector2D的二維坐標(biāo)向量 (x,y) 的結(jié)構(gòu),然后定義了讓兩個(gè)Vector2D的對(duì)象相加的運(yùn)算符函數(shù)。

struct Vector2D { 
    var x = 0.0, y = 0.0 
} 
func + (left: Vector2D, right: Vector2D) -> Vector2D { 
    return Vector2D(x: left.x + right.x, y: left.y + right.y) 
} 
  • 在這個(gè)代碼實(shí)現(xiàn)中,參數(shù)被命名為了left和right,代表+左邊和右邊的兩個(gè)Vector2D對(duì)象。函數(shù)返回了一個(gè)新的Vector2D的對(duì)象,這個(gè)對(duì)象的x和y分別等于兩個(gè)參數(shù)對(duì)象的x和y的和。

  • 這個(gè)函數(shù)是全局的,而不是Vector2D結(jié)構(gòu)的成員方法,所以任意兩個(gè)Vector2D對(duì)象都可以使用這個(gè)中置運(yùn)算符。

let v1 = Vector2D(x: 1, y: 2)
let v2 = Vector2D(x: 3, y: 4)
print(v1 + v2)        // 打印: Vector2D(x: 4.0, y: 6.0)
2、前置和后置運(yùn)算符
  • 上個(gè)例子演示了一個(gè)雙目中置運(yùn)算符的自定義實(shí)現(xiàn),同樣我們也可以玩標(biāo)準(zhǔn)單目運(yùn)算符的實(shí)現(xiàn)。單目運(yùn)算符只有一個(gè)操作數(shù),在操作數(shù)之前就是前置的,如-a; 在操作數(shù)之后就是后置的,如i++。

  • 實(shí)現(xiàn)一個(gè)前置或后置運(yùn)算符時(shí),在定義該運(yùn)算符的時(shí)候于關(guān)鍵字func之前標(biāo)注 prefixpostfix 屬性。

  • 下面實(shí)現(xiàn)-取反運(yùn)算符

prefix func - (vector: Vector2D) -> Vector2D { 
    return Vector2D(x: -vector.x, y: -vector.y) 
} 
  • 調(diào)用
print(-v1)        // 打印: Vector2D(x: -1.0, y: -2.0)
3、組合賦值運(yùn)算符
  • 組合賦值是其他運(yùn)算符和賦值運(yùn)算符一起執(zhí)行的運(yùn)算。如+=把加運(yùn)算和賦值運(yùn)算組合成一個(gè)操作
func += (inout left: Vector2D, right: Vector2D) { 
    left = left + right 
} 
  • 因?yàn)榧臃ㄟ\(yùn)算在之前定義過了,這里無需重新定義。所以,加賦運(yùn)算符函數(shù)使用已經(jīng)存在的高級(jí)加法運(yùn)算符函數(shù)來執(zhí)行左值加右值的運(yùn)算。
var a = Vector2D(x: 1.0, y: 2.0) 
let b = Vector2D(x: 3.0, y: 4.0) 
a += b 
// a 現(xiàn)在為 (4.0, 6.0) 

注意:默認(rèn)的賦值符(=)是不可重載的。只有組合賦值符可以重載。三目條件運(yùn)算符 (a ? b : c) 也是不可重載。

4、等價(jià)運(yùn)算符
  • 定義的類和結(jié)構(gòu)體沒有對(duì)等價(jià)運(yùn)算符進(jìn)行默認(rèn)實(shí)現(xiàn),等價(jià)運(yùn)算符通常被稱為“相等”運(yùn)算符(==)與“不等”運(yùn)算符(!=)。對(duì)于自定義類型,Swift 無法判斷其是否“相等”,因?yàn)椤跋嗟取钡暮x取決于這些自定義類型在你的代碼中所扮演的角色。

  • 為了使用等價(jià)運(yùn)算符能對(duì)自定義的類型進(jìn)行判等運(yùn)算,需要為其提供自定義實(shí)現(xiàn),實(shí)現(xiàn)的方法與其它中綴運(yùn)算符一樣, 并且增加對(duì)標(biāo)準(zhǔn)庫 Equatable 協(xié)議的遵循:

extension Vector2D: Equatable {
    static func == (left: Vector2D, right: Vector2D) -> Bool {
        return (left.x == right.x) && (left.y == right.y)
    }
}
  • 上述代碼實(shí)現(xiàn)了“相等”運(yùn)算符(==)來判斷兩個(gè) Vector2D 實(shí)例是否相等。對(duì)于 Vector2D 類型來說,“相等”意味著“兩個(gè)實(shí)例的 x 屬性和 y 屬性都相等”,這也是代碼中用來進(jìn)行判等的邏輯。

示例里同時(shí)也實(shí)現(xiàn)了“不等”運(yùn)算符(!=),它簡(jiǎn)單地將“相等”運(yùn)算符的結(jié)果進(jìn)行取反后返回。

  • 現(xiàn)在我們可以使用這兩個(gè)運(yùn)算符來判斷兩個(gè) Vector2D 實(shí)例是否相等:
let twoThree = Vector2D(x: 2.0, y: 3.0)
let anotherTwoThree = Vector2D(x: 2.0, y: 3.0)
if twoThree == anotherTwoThree {
    print("These two vectors are equivalent.")
}
// 打印 “These two vectors are equivalent.”
  • Swift 為以下自定義類型提等價(jià)運(yùn)算符供合成實(shí)現(xiàn):
只擁有遵循 Equatable 協(xié)議存儲(chǔ)屬性的結(jié)構(gòu)體;
只擁有遵循 Equatable 協(xié)議關(guān)聯(lián)類型的枚舉;
沒有關(guān)聯(lián)類型的枚舉。
  • 在類型原本的聲明中聲明遵循 Equatable 來接收這些默認(rèn)實(shí)現(xiàn)。

  • 下面為三維位置向量 (x, y, z) 定義的 Vector3D 結(jié)構(gòu)體,與 Vector2D 類似,由于 x,yz 屬性都是 Equatable 類型,Vector3D 就收到默認(rèn)的等價(jià)運(yùn)算符實(shí)現(xiàn)了。

struct Vector3D: Equatable {
    var x = 0.0, y = 0.0, z = 0.0
}

let twoThreeFour = Vector3D(x: 2.0, y: 3.0, z: 4.0)
let anotherTwoThreeFour = Vector3D(x: 2.0, y: 3.0, z: 4.0)
if twoThreeFour == anotherTwoThreeFour {
    print("These two vectors are also equivalent.")
}
// Prints "These two vectors are also equivalent."

五、自定義運(yùn)算符

  • Swift 中還可以聲明和實(shí)現(xiàn)自定義運(yùn)算符。

注意
以下這些標(biāo)記 =->、//、/*、*/、.、<(前綴運(yùn)算符)、&、?、?(中綴運(yùn)算符)、>(后綴運(yùn)算符)、!? 是被系統(tǒng)保留的。這些符號(hào)不能被重載,也不能用于自定義運(yùn)算符。

  • 新的運(yùn)算符要使用 operator 關(guān)鍵字在全局作用域內(nèi)進(jìn)行定義,同時(shí)還要指定 prefix、infix 或者 postfix 修飾符:
prefix:    前置運(yùn)算符
infix:     中置運(yùn)算符
postfix:   后置運(yùn)算符
prefix operator +++
  • 上面的代碼定義了一個(gè)新的名為 +++ 的前綴運(yùn)算符。對(duì)于這個(gè)運(yùn)算符,在 Swift 中并沒有意義,因此我們針對(duì) Vector2D 的實(shí)例來定義它的意義。
extension Vector2D {
    static prefix func +++ (vector: inout Vector2D) -> Vector2D {
        vector += vector
        return vector
    }
}

var toBeDoubled = Vector2D(x: 1.0, y: 4.0)
let afterDoubling = +++toBeDoubled
// toBeDoubled 現(xiàn)在的值為 (2.0, 8.0)
// afterDoubling 現(xiàn)在的值也為 (2.0, 8.0)
1、自定義中綴運(yùn)算符的優(yōu)先級(jí)
  • 每個(gè)自定義中綴運(yùn)算符都屬于某個(gè)優(yōu)先級(jí)組。這個(gè)優(yōu)先級(jí)組指定了這個(gè)運(yùn)算符和其他中綴運(yùn)算符的優(yōu)先級(jí)和結(jié)合性。

  • 而沒有明確放入優(yōu)先級(jí)組的自定義中綴運(yùn)算符會(huì)放到一個(gè)默認(rèn)的優(yōu)先級(jí)組內(nèi),其優(yōu)先級(jí)高于三元運(yùn)算符。

  • 以下例子定義了一個(gè)新的自定義中綴運(yùn)算符 +-,此運(yùn)算符屬于 AdditionPrecedence 優(yōu)先組:

infix operator +-: AdditionPrecedence
extension Vector2D {
    static func +- (left: Vector2D, right: Vector2D) -> Vector2D {
        return Vector2D(x: left.x + right.x, y: left.y - right.y)
    }
}
let firstVector = Vector2D(x: 1.0, y: 2.0)
let secondVector = Vector2D(x: 3.0, y: 4.0)
let plusMinusVector = firstVector +- secondVector
// plusMinusVector 是一個(gè) Vector2D 實(shí)例,并且它的值為 (4.0, -2.0)
2、定義優(yōu)先級(jí)別名
  • 可以使用下面的方式, 自定義操作符的優(yōu)先級(jí), 這依賴于已有優(yōu)先級(jí), 比如下面的AdditionPrecedenceMultiplicationPrecedence
// >>>操作符, 優(yōu)先級(jí)別名
infix operator >>> : ATPrecedence
precedencegroup ATPrecedence { //定義運(yùn)算符優(yōu)先級(jí)ATPrecedence
    associativity: left 
    higherThan: AdditionPrecedence 
    lowerThan: MultiplicationPrecedence
}
  • 直接指定操作符的類型,對(duì)這個(gè)類型進(jìn)行定義
associativity: left 表示左結(jié)合
higherThan 優(yōu)先級(jí)高于 AdditionPrecedence 這個(gè)是加法的類型
lowerThan 優(yōu)先級(jí)低于 MultiplicationPrecedence 乘除
  • 這里給出常用類型對(duì)應(yīng)的group
infix operator || : LogicalDisjunctionPrecedence
infix operator && : LogicalConjunctionPrecedence
infix operator < : ComparisonPrecedence
infix operator <= : ComparisonPrecedence
infix operator > : ComparisonPrecedence
infix operator >= : ComparisonPrecedence
infix operator == : ComparisonPrecedence
infix operator != : ComparisonPrecedence
infix operator === : ComparisonPrecedence
infix operator !== : ComparisonPrecedence
infix operator ~= : ComparisonPrecedence
infix operator ?? : NilCoalescingPrecedence
infix operator + : AdditionPrecedence
infix operator - : AdditionPrecedence
infix operator &+ : AdditionPrecedence
infix operator &- : AdditionPrecedence
infix operator | : AdditionPrecedence
infix operator ^ : AdditionPrecedence
infix operator * : MultiplicationPrecedence
infix operator / : MultiplicationPrecedence
infix operator % : MultiplicationPrecedence
infix operator &* : MultiplicationPrecedence
infix operator & : MultiplicationPrecedence
infix operator << : BitwiseShiftPrecedence
infix operator >> : BitwiseShiftPrecedence
infix operator ..< : RangeFormationPrecedence
infix operator ... : RangeFormationPrecedence
infix operator *= : AssignmentPrecedence
infix operator /= : AssignmentPrecedence
infix operator %= : AssignmentPrecedence
infix operator += : AssignmentPrecedence
infix operator -= : AssignmentPrecedence
infix operator <<= : AssignmentPrecedence
infix operator >>= : AssignmentPrecedence
infix operator &= : AssignmentPrecedence
infix operator ^= : AssignmentPrecedence
infix operator |= : AssignmentPrecedence
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容