swift面試題

?class 和 struct 的區(qū)別

class 為類, struct 為結(jié)構(gòu)體, 類是引用類型, 結(jié)構(gòu)體為值類型, 結(jié)構(gòu)體不可以繼承

不通過繼承,代碼復(fù)用(共享)的方式有哪些

擴(kuò)展, 全局函數(shù)

Set 獨(dú)有的方法有哪些?

// 定義一個 set
let setA: Set<Int> = [1, 2, 3, 4, 4]
// {1, 2, 3, 4}, 順序可能不一致, 同一個元素只有一個值
?let setB: Set<Int> = [1, 3, 5, 7, 9]
// {1, 3, 5, 7, 9}
// 取并集 A | B
let setUnion = setA.union(setB)
// {1, 2, 3, 4, 5, 7, 9}
// 取交集 A & B
let setIntersect = setA.intersection(setB)
// {1, 3}
// 取差集 A - B
let setRevers = setA.subtracting(setB)
// {2, 4}
// 取對稱差集, A XOR B = A - B | B - A
let setXor = setA.symmetricDifference(setB)
//{2, 4, 5, 7, 9}

實(shí)現(xiàn)一個 min 函數(shù),返回兩個元素較小的元素

Comparable?可以使用關(guān)系運(yùn)算符<,<=,> =和>進(jìn)行比較的類型。

func myMin<T: Comparable>(_ a: T, _ b: T) -> T {
?return a < b ? a : b
}
myMin(1, 2)

map、filter、reduce 的作用

map 用于映射, 可以將一個列表轉(zhuǎn)換為另一個列表

[1, 2, 3].map{"\($0)"}// 數(shù)字?jǐn)?shù)組轉(zhuǎn)換為字符串?dāng)?shù)組
["1", "2", "3"]

filter 用于過濾, 可以篩選出想要的元素

[1,2,3].filter{$0 %2==0}// 篩選偶數(shù)
// [2]

reduce 合并

// 轉(zhuǎn)換為字符串并拼接
[1,2,3].reduce(""){$0 +"\($1)"}// "123"

組合示例

(0..<10).filter{$0 %2==0}.map{"\($0)"}.reduce(""){$0 + $1}
// 02468

map 與 flatmap 的區(qū)別

flatmap 有兩個實(shí)現(xiàn)函數(shù)實(shí)現(xiàn),

public?func?flatMap(_transform: (Element)?throws->ElementOfResult?)?rethrows?->? [ElementOfResult]

這個方法, 中間的函數(shù)返回值為一個可選值, 而 flatmap 會丟掉那些返回值為nil的值
例如

["1","@","2","3","a"].flatMap{Int($0)}
// [1, 2, 3]
["1","@","2","3","a"].map{Int($0) ??-1}
//[Optional(1), nil, Optional(2), Optional(3), nil]

另一個實(shí)現(xiàn)

public?func?flatMap(_transform: (Element)?throws?-> SegmentOfResult)?rethrows?->? [SegmentOfResult.Iterator.Element]?where?SegmentOfResult : Sequence

中間的函數(shù), 返回值為一個數(shù)組, 而這個 flapmap 返回的對象則是一個與自己元素類型相同的數(shù)組

func?someFunc(_array:[Int]) -> [Int] {
? ??return?array
}
[[1], [2,3], [4,5,6]].map(someFunc)
// [[1], [2, 3], [4, 5, 6]]
[[1], [2,3], [4,5,6]].flatMap(someFunc)
// [1, 2, 3, 4, 5, 6]

其實(shí)這個實(shí)現(xiàn), 相當(dāng)于是在使用 map 之后, 再將各個數(shù)組拼起來一樣的

[[1], [2,3], [4,5,6]].map(someFunc).reduce([Int]()) {$0 + $1}
// [1, 2, 3, 4, 5, 6]

什么是 copy on write時候

寫時復(fù)制, 指的是 swift 中的值類型, 并不會在一開始賦值的時候就去復(fù)制, 只有在需要修改的時候, 才去復(fù)制.
這里有詳細(xì)的說明
http://www.itdecent.cn/p/7e8ba0659646

如何獲取當(dāng)前代碼的函數(shù)名和行號

#file用于獲取當(dāng)前文件文件名
#line用于獲取當(dāng)前行號
#column用于獲取當(dāng)前列編號
#function用于獲取當(dāng)前函數(shù)名
以上這些都是特殊的字面量, 多用于調(diào)試輸出日志
具體可以看這里 apple 文檔
https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html
這里有中文翻譯

http://wiki.jikexueyuan.com/project/swift/chapter3/04_Expressions.html

如何聲明一個只能被類 conform 的protocol

聲明協(xié)議的時候, 加一個class即可

protocol?SomeClassProtocl:class {
? ?func?someFunction()
}

guard 使用場景

guardif類似, 不同的是,guard總是有一個else語句, 如果表達(dá)式是假或者值綁定失敗的時候, 會執(zhí)行else語句, 且在else語句中一定要停止函數(shù)調(diào)用

例如

guard1+1==2else{
? ? fatalError("something wrong")
}

常用使用場景為, 用戶登錄的時候, 驗(yàn)證用戶是否有輸入用戶名密碼等

guard?let?userName =?self.userNameTextField.text,
? ??let?password =?self.passwordTextField.text?else{
? ? ? ??return
}

defer 使用場景

defer語句塊中的代碼, 會在當(dāng)前作用域結(jié)束前調(diào)用, 常用場景如異常退出后, 關(guān)閉數(shù)據(jù)庫連接

func?someQuery() -> ([Result], [Result]){
? ??let?db = DBOpen("xxx")
? ??defer{
? ? ? ? db.close()
? ? }
? ??guard?results1 = db.query("query1")?else?{
? ? ? ??return nil
? ? }
? ??guard?results2 = db.query("query2")?else?{
? ? ? ??return nil
? ? }
? ??return(results1, results2)
}

需要注意的是, 如果有多個defer, 那么后加入的先執(zhí)行

func?someDeferFunction() {
? ??defer{
? ? ? ? print("\(#function)-end-1-1")
? ? ? ? print("\(#function)-end-1-2")
? ? }
? ??defer{
? ? ? ? print("\(#function)-end-2-1")
? ? ? ? print("\(#function)-end-2-2")
? ? }
? ??if?true{
? ? ? ??defer{
? ? ? ? ? ? print("if defer")
? ? ? ? }
? ? ? ? print("if end")
? ? }
? ? print("function end")
}
someDeferFunction()
// 輸出
// if end
// if defer
// function end
// someDeferFunction()-end-2-1
// someDeferFunction()-end-2-2
// someDeferFunction()-end-1-1
// someDeferFunction()-end-1-2

String 與 NSString 的關(guān)系與區(qū)別

NSString 與 String 之間可以隨意轉(zhuǎn)換,

let?someString ="123"
let?someNSString =NSString(string:"n123")
let?strintToNSString =someString?as?NSString
let?nsstringToString =someNSString?as?String

String是結(jié)構(gòu)體, 值類型, NSString 是類, 引用類型.
通常, 沒必要使用 NSString 類, 除非你要使用一些特有方法, 例如使用 pathExtension 屬性
怎么獲取一個 String 的長度
不考慮編碼, 只是想知道字符的數(shù)量, 用characters.count

"hello".characters.count// 5
"你好".characters.count// 2
"こんにちは".characters.count// 5

如果想知道在某個編碼下占多少字節(jié), 可以用

"hello".lengthOfBytes(using: .ascii)// 5|
"hello".lengthOfBytes(using: .unicode)// 10
"你好".lengthOfBytes(using: .unicode)// 4
"你好".lengthOfBytes(using: .utf8)// 6
"こんにちは".lengthOfBytes(using: .unicode)// 10
"こんにちは".lengthOfBytes(using: .utf8)// 15

如何截取 String 的某段字符串

swift 中, 有三個取子串函數(shù),

substring:to , substring:from, substring:with.
let?simpleString ="Hello, world"
simpleString.substring(to: simpleString.index(simpleString.startIndex, offsetBy: 5))
// hello
simpleString.substring(from: simpleString.index(simpleString.endIndex, offsetBy: -5))
// world
simpleString.substring(with: simpleString.index(simpleString.startIndex, offsetBy: 5) ..< simpleString.index(simpleString.endIndex, offsetBy: -5))

使用起來略微麻煩, 具體用法可以參考這一篇文章
http://www.itdecent.cn/p/b3231f9406e9

throwsrethrows 的用法與作用

throws用在函數(shù)上, 表示這個函數(shù)會拋出錯誤.
有兩種情況會拋出錯誤, 一種是直接使用throw拋出, 另一種是調(diào)用其他拋出異常的函數(shù)時, 直接使用tryxx 沒有處理異常.

enumDivideError:Error{
? ??caseEqualZeroError;
}
func?divide(_a:Double,_b:Double)throws->Double{
? ??guard?b !=Double(0)else{
? ? ? ??throw DivideError.EqualZeroError
? ? }
? ??returna / b
}
func?split(pieces:Int)throws->Double{
? ??return?try?divide(1,Double(pieces))
}

rethrowsthrows類似, 不過只適用于參數(shù)中有函數(shù), 且函數(shù)會拋出異常的情況,rethrows可以用throws替換, 反過來不行

func?processNumber(a:Double, b:Double, function: (Double,Double)throws->Double)rethrows->Double{
? ??return?try?function(a, b)
}

try? 和 try!是什么意思

這兩個都用于處理可拋出異常的函數(shù), 使用這兩個關(guān)鍵字可以不用寫docatch.
區(qū)別在于,try? 在用于處理可拋出異常函數(shù)時, 如果函數(shù)拋出異常, 則返回nil, 否則返回函數(shù)返回值的可選值, 如:

print(try? divide(2,1))
// Optional(2.0)
print(try? divide(2,0))
// nil

try! 則在函數(shù)拋出異常的時候崩潰, 否則則返會函數(shù)返回值, 相當(dāng)于(try? xxx)!, 如:

print(try! divide(2,1))
// 2.0
print(try! divide(2,0))
// 崩潰

associatedtype 的作用

簡單來說就是protocol使用的泛型
例如定義一個列表協(xié)議

protocol?ListProtcol {
? ??associatedtype Element
? ??func?push(_element:Element)
? ??func?pop(_element:Element) ->Element?
}

實(shí)現(xiàn)協(xié)議的時候, 可以使用typealias指定為特定的類型, 也可以自動推斷, 如

class?IntList : ListProtcol{
? ??typealias Element = Int // 使用 typealias 指定為 Int
? ??var?list = [Element]()
? ??func?push(_element:Element) {
? ? ? ??self.list.append(element)
? ? }
? ??func?pop(_element:Element) ->Element? {
? ? ? ??return?self.list.popLast()
? ? }
}

class?DoubleList:ListProtcol{
? ??var?list = [Double]()
? ??func?push(_element:Double) {// 自動推斷
? ? ? ??self.list.append(element)
? ? }
? ??func?pop(_element:Double) ->Double? {
? ? ? ??return?self.list.popLast()
? ? }
}

使用泛型也可以

class?AnyList:ListProtcol{
? ??var?list = [T]()
? ??func?push(_element:T) {
? ? ? ??self.list.append(element)
? ? }
? ??func?pop(_element:T) ->T? {
? ? ? ??return?self.list.popLast()
? ? }
}

可以使用where字句限定 Element 類型, 如:

extension ListProtcol where Element == Int {
? ??func?isInt() ->Bool{
? ? ? ??return true
? ? }
}

什么時候使用 final

final 用于限制繼承和重寫. 如果只是需要在某一個屬性前加一個 final.
如果需要限制整個類無法被繼承, 那么可以在類名之前加一個final
public和 open 的區(qū)別
這兩個都用于在模塊中聲明需要對外界暴露的函數(shù), 區(qū)別在于,public修飾的類, 在模塊外無法繼承, 而 open 則可以任意繼承, 公開度來說,public< open
聲明一個只有一個參數(shù)沒有返回值閉包的別名
沒有返回值也就是返回值為 Void

typealias?SomeClosuerType = (String) -> (Void)
let?someClosuer:SomeClosuerType= { (name:String)in
? ? print("hello,", name)
}
someClosuer("world")
// hello, world

Self的使用場景

Self通常在協(xié)議中使用, 用來表示實(shí)現(xiàn)者或者實(shí)現(xiàn)者的子類類型.
例如, 定義一個復(fù)制的協(xié)議

protocolCopyProtocol {
? ??func?copy() ->Self
}

如果是結(jié)構(gòu)體去實(shí)現(xiàn), 要將Self 換為具體的類型

structSomeStruct:CopyProtocol{
? ??let?value:Int
? ??func?copySelf() ->SomeStruct{
? ? ? ??returnSomeStruct(value:self.value)
? ? }
}

如果是類去實(shí)現(xiàn), 則有點(diǎn)復(fù)雜, 需要有一個 required 初始化方法, 具體可以看這里 http://swifter.tips/use-self/

class?SomeCopyableClass:CopyProtocol{
? ??func?copySelf() ->Self{
? ? ? ??return?type(of:self).init()
? ? }
? ??required init(){}
}

dynamic 的作用

由于 swift 是一個靜態(tài)語言, 所以沒有 Objective-C 中的消息發(fā)送這些動態(tài)機(jī)制, dynamic 的作用就是讓 swift 代碼也能有 Objective-C 中的動態(tài)機(jī)制, 常用的地方就是 KVO 了, 如果要監(jiān)控一個屬性, 則必須要標(biāo)記為 dynamic, 可以參考我的文章http://www.itdecent.cn/p/ae26100b9edf

什么時候使用@objc

@objc用途是為了在 Objective-C 和 Swift 混編的時候, 能夠正常調(diào)用 Swift 代碼. 可以用于修飾類, 協(xié)議, 方法, 屬性.
常用的地方是在定義 delegate 協(xié)議中, 會將協(xié)議中的部分方法聲明為可選方法, 需要用到@objc

@objcprotocol?OptionalProtocol {
? ??@objcoptional?func?optionalFunc()
? ??func?normalFunc()
}
class?OptionProtocolClass:OptionalProtocol{
? ??func?normalFunc() {
? ? }
}
let?someOptionalDelegate:OptionalProtocol=OptionProtocolClass()
someOptionalDelegate.optionalFunc?()

Optional(可選型) 是用什么實(shí)現(xiàn)的

Optional 是一個泛型枚舉
大致定義如下:

enum?Optional {
? ??case?none
? ??case?some(Wrapped)
}

除了使用let?someValue:Int? =nil之外, 還可以使用let optional1: Optional =nil來定義

如何自定義下標(biāo)獲取

實(shí)現(xiàn) subscript 即可, 如

extension AnyList {
? ??subscript(index:Int) ->T{
? ? ? ??return?self.list[index]
? ? }
? ??subscript(indexString:String) ->T?{
? ? ? ??guard?let?index =Int(indexString)else{
? ? ? ? ? ??return nil
? ? ? ? }
? ? ? ??return?self.list[index]
? ? }
}

索引除了數(shù)字之外, 其他類型也是可以的

?? 的作用

可選值的默認(rèn)值, 當(dāng)可選值為nil 的時候, 會返回后面的值. 如

let?someValue = optional1 ??0

lazy 的作用

懶加載, 當(dāng)屬性要使用的時候, 才去完成初始化

class?LazyClass {
? ??lazy?var?someLazyValue:Int= {
? ? ? ? print("lazy init value")
? ? ? ??return1
? ? }()
? ??var?someNormalValue:Int= {
? ? ? ? print("normal init value")
? ? ? ??return2
? ? }()
}

let?lazyInstance =LazyClass()
print(lazyInstance.someNormalValue)|
print(lazyInstance.someLazyValue)
// 打印輸出
// normal init value
// 2
// lazy init value
// 1

一個類型表示選項,可以同時表示有幾個選項選中(類似 UIViewAnimationOptions ),用什么類型表示

需要實(shí)現(xiàn)自O(shè)ptionSet, 一般使用struct實(shí)現(xiàn). 由于 OptionSet 要求有一個不可失敗的init(rawValue:) 構(gòu)造器, 而 枚舉無法做到這一點(diǎn)(枚舉的原始值構(gòu)造器是可失敗的, 而且有些組合值, 是沒辦法用一個枚舉值表示的)

struct?SomeOption:OptionSet{
? ??let?rawValue:Int
? ??static?let?option1 =SomeOption(rawValue:1<<0)
? ??static?let?option2 =? SomeOption(rawValue:1<<1)
? ??static?let?option3 =? SomeOption(rawValue:1<<2)
}
let options: SomeOption = [.option1, .option2]

inout 的作用

輸入輸出參數(shù), 如:

func?swap( a:inoutInt, b:inoutInt) {
? ??let?temp = a
? ? a = b
? ? b = temp
}
var?a =1
var?b =2
print(a, b)// 1 2
swap(a: &a, b: &b)
print(a, b)// 2 1

Error如果要兼容NSError需要做什么操作

其實(shí)直接轉(zhuǎn)換就可以, 例如 SomeError.someError?as?NSError 但是這樣沒有錯誤碼, 描述等等, 如果想和 NSError 一樣有這些東西, 只需要實(shí)現(xiàn) LocalizedError 和 CustomNSError 協(xié)議, 有些方法有默認(rèn)實(shí)現(xiàn), 可以略過, 如:

enum SomeError: Error, LocalizedError, CustomNSError {
? ??caseerror1, error2
? ??public?var?errorDescription:String? {
? ? ? ??switch?self{
? ? ? ??case.error1:
? ? ? ? ? ??return "error description error1"
? ? ? ??case.error2:
? ? ? ? ? ??return "error description error2"
? ? ? ? }
? ? }

? ? var?errorCode:Int{
? ? ? ??switch?self{
? ? ? ??case.error1:
? ? ? ? ? ??return1
? ? ? ??case.error2:
? ? ? ? ? ??return2
? ? ? ? }
? ? }

? ? public?static?var?errorDomain:String{
? ? ? ??return "error domain SomeError"
? ? }

? ? public?var?errorUserInfo: [String:Any] {
? ? ? ??switchself{
? ? ? ??case.error1:
? ? ? ? ? ??return["info":"error1"]
? ? ? ??case.error2:
? ? ? ? ? ??return["info":"error2"]
? ? ? ? }
? ? }
}

print(SomeError.error1 as NSError)
// Error Domain=error domain SomeError Code=1 "error description error1" UserInfo={info=error1}

下面的代碼都用了哪些語法糖

[1,2,3].map{ $0 *2}

[1,2,3] 使用了, Array 實(shí)現(xiàn)的ExpressibleByArrayLiteral 協(xié)議, 用于接收數(shù)組的字面值
map{xxx} 使用了閉包作為作為最后一個參數(shù)時, 可以直接寫在調(diào)用后面, 而且, 如果是唯一參數(shù)的話, 圓括號也可以省略
閉包沒有聲明函數(shù)參數(shù), 返回值類型, 數(shù)量, 依靠的是閉包類型的自動推斷
閉包中語句只有一句時, 自動將這一句的結(jié)果作為返回值0, 后續(xù)參數(shù)以此類推

什么是高階函數(shù)

一個函數(shù)如果可以以某一個函數(shù)作為參數(shù), 或者是返回值, 那么這個函數(shù)就稱之為高階函數(shù), 如 map, reduce, filter

如何解決引用循環(huán)

轉(zhuǎn)換為值類型, 只有類會存在引用循環(huán), 所以如果能不用類, 是可以解引用循環(huán)的,
delegate 使用 weak 屬性.
閉包中, 對有可能發(fā)生循環(huán)引用的對象, 使用 weak 或者 unowned, 修飾

下面的代碼會不會崩潰,說出原因

var?mutableArray = [1,2,3]
for _ in mutableArray {
? ? mutableArray.removeLast()
}

不會, 原理不清楚, 就算是把 removeLast(), 換成 removeAll() ,這個循環(huán)也會執(zhí)行三次, 估計是在一開始,for?in就對 mutableArray 進(jìn)行了一次值捕獲, 而 Array 是一個值類型 , removeLast() 并不能修改捕獲的值.

給集合中元素是字符串的類型增加一個擴(kuò)展方法,應(yīng)該怎么聲明

使用where子句, 限制 Element 為 String

extension Array where Element == String {
? ??var?isStringElement:Bool{
? ? ? ??return true
? ? }
}
["1", "2"].isStringElement
//[1, 2].isStringElement// error

定義靜態(tài)方法時關(guān)鍵字staticclass有什么區(qū)別

static定義的方法不可以被子類繼承,class則可以

class?AnotherClass {
? ??static?func?staticMethod(){}
? ??class?func?classMethod(){}
}
class?ChildOfAnotherClass:AnotherClass{
? ??override?class?func?classMethod(){}
? ??//override static func staticMethod(){}// error
}

一個Sequence的索引是不是一定從0開始?

不一定, 兩個forin并不能保證都是從0開始, 且輸出結(jié)果一致, 官方文檔如下

Repeated Access
The Sequence?protocol?makes no requirement on conforming types regarding whether they will be destructively consumed by iteration. As aconsequence, don't assume that multiple for-in loops on a sequence will either resume iteration or restart from the beginning:

for?element?in?sequence {
? ? ? ??if... some condition {break}
}
for?element?in?sequence {
? ??// No defined behavior
}

有些同學(xué)還是不太理解, 我寫了一個demo 當(dāng)作參考

class Countdown: Sequence, IteratorProtocol {
? ??var?count:Int
? ??init(count:Int) {
? ? ? ??self.count= count
? ? }
? ??func?next() ->Int? {
? ? ? ??if?count==0{
? ? ? ? ? ??return?nil
? ? ? ? }else{
? ? ? ? ? ??defer{count-=1}
? ? ? ? ? ??return?count
? ? ? ? }
? ? }
}
var?countDown =Countdown(count:5)
print("begin for in 1")
for c in countDown {
? ? print(c)
}
print("end for in 1")
print("begin for in 2")
for c in countDown {
? ? print(c)
}
print("end for in 2")
最后輸出的結(jié)果是
begin?for?in?1
end?for?in?1
begin?for?in?2
end?for?in?2

很明顯, 第二次沒有輸出任何結(jié)果, 原因就是在第二次forin的時候, 并沒有將count 重置.

數(shù)組都實(shí)現(xiàn)了哪些協(xié)議

MutableCollection, 實(shí)現(xiàn)了可修改的數(shù)組, 如 a[1] =2
ExpressibleByArrayLiteral, 實(shí)現(xiàn)了數(shù)組可以從[1,2,3] 這種字面值初始化的能力
...

如何自定義模式匹配

這部分不太懂, 貼個鏈接吧
http://swifter.tips/pattern-match/

autoclosure 的作用

自動閉包, 會自動將某一個表達(dá)式封裝為閉包. 如

func?autoClosureFunction(_closure:@autoclosure() ->Int) {
? ? closure()
}
autoClosureFunction(1)

詳細(xì)可參考http://swifter.tips/autoclosure/

編譯選項 whole module optmization 優(yōu)化了什么

編譯器可以跨文件優(yōu)化編譯代碼, 不局限于一個文件.

http://www.itdecent.cn/p/8dbf2bb05a1c

下面代碼中 mutating 的作用是什么

struct?Person {
? ??var?name:String{
? ? ? ??mutating get {
? ? ? ? ? ??return?store
? ? ? ? }
? ? }
}

讓不可變對象無法訪問 name 屬性

如何讓自定義對象支持字面量初始化

有幾個協(xié)議, 分別是

ExpressibleByArrayLiteral 可以由數(shù)組形式初始化
ExpressibleByDictionaryLiteral 可以由字典形式初始化
ExpressibleByNilLiteral 可以由nil 值初始化
ExpressibleByIntegerLiteral 可以由整數(shù)值初始化
ExpressibleByFloatLiteral 可以由浮點(diǎn)數(shù)初始化
ExpressibleByBooleanLiteral 可以由布爾值初始化
ExpressibleByUnicodeScalarLiteral
ExpressibleByExtendedGraphemeClusterLiteral
ExpressibleByStringLiteral
這三種都是由字符串初始化, 上面兩種包含有 Unicode 字符和特殊字符

dynamic framework 和static?framework 的區(qū)別是什么

靜態(tài)庫和動態(tài)庫, 靜態(tài)庫是每一個程序單獨(dú)打包一份, 而動態(tài)庫則是多個程序之間共享
鏈接:? ?http://www.itdecent.cn/p/7c7f4b4e4efe
鏈接:http://www.itdecent.cn/p/cc4a737ddc1d
鏈接:http://www.itdecent.cn/p/23d99f434281

原文地址 :?http://www.itdecent.cn/p/a70841d17fb2

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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