Swift 編碼規(guī)范

溫德里奇規(guī)范

本規(guī)范原文鏈接.

規(guī)范只是一些最佳實踐, 請酌情使用.

1 正確性

第一條原則, 也是最根本的原則: 應努力使代碼在編譯時沒有任何的警告. 這就涉及到諸多的設計決定和實現(xiàn)途徑的選擇.

2 命名規(guī)則

命名時應做到見名知意, 且必須保證意義一致性.

下面列出的命名規(guī)則摘錄自蘋果的 API design guideline, 是其中一些主要的規(guī)則:

  • 函數(shù)或方法名稱必須能夠清晰描述該函數(shù)或者方法的內(nèi)容或功能
  • 為了表達更加清楚, 可以適當放寬簡潔性要求.
  • 使用駝峰命名法.
  • 使用駝峰命名法的時候就兩種規(guī)則: 除了類型的名稱開頭是大寫字母外, 其他的都是以小寫字母開頭.
  • 在滿足上述規(guī)則的前提下, 盡量做到表達簡潔.
  • 命名的時候是基于實體的抽象含義, 而非基于其類型.
  • 保證抽象含義表達清楚的基礎上, 適當增加類型信息.
  • 保證命名后, 實體在使用上的流暢性. (這個需要技巧, 比如命名了一個東西, 找好久找不到, 想好久想不起來叫什么, 這樣就會造成在使用上的不流暢)
  • 工廠方法以單詞 make 開頭.
  • 方法名稱中需要包含描述其功能的附加效應的詞:(這個不易理解, 需參考 API 設計準則再加以詳細描述)
  • 使用專業(yè)術(shù)語或名詞的時候, 盡量做到不要 "讓知道的人笑掉大牙, 讓不知道的人不知所云".
  • 命名時盡量不要使用縮寫, 特別是那些比較生僻的縮寫或者是自己發(fā)明的縮寫.
  • 命名時做到有據(jù)可依, 要有先例最好?. (這個需參考 API 設計準則再加以詳細描述)
  • 盡量使用屬性和方法, 不要使用沒有處于特定命名空間中的變量或函數(shù).
  • 縮略語的大小寫方針要統(tǒng)一, 要么統(tǒng)一大寫, 要么統(tǒng)一小寫.
  • 具有相似含義的若干方法, 當應用場景不同的時候, 它們的名稱需要附加描述含義的相同的前綴或后綴.
  • swift中支持基于不同返回值時候的重載, 但是需要極力避免這樣的重載發(fā)生.
  • 使用文檔化的參數(shù)命名.
  • 為閉包或元組的參數(shù)提供標簽.
  • 盡量利用參數(shù)的默認值, 能省很多事.(比如可選參數(shù)的默認值是nil, 就不用再在外界傳參時候再傳入一個nil了.)

2.1 Prose

2.2 不要添加類型名前綴

由于 swift 中使用 module 作為一個名字空間, 而 module 名字唯一, 所以類名沖突是不存在的. 即使兩個 module 中有相同的類名, 也可以通過 module名.類名 加以區(qū)分, 并且只有在有相同類名的時候才需要使用這樣方式.

import SomeModule

let myClass = MyModule.UsefulClass()

基于上述事實, swift 中不要再使用類名前綴了.

2.3 代理方法命名

當自定義代理時, 代理方法的第一個參數(shù)應該是代理源, 且沒有參數(shù)標簽, 保證和原生代碼中的代理方法命名方式的一致性:

應該:

func namePickerView(_ namePickerView: NamePickerView, didSelectName name: String)
func namePickerViewShouldReload(_ namePickerView: NamePickerView) -> Bool

不應:

func didSelectName(namePicker: NamePickerViewController, name: String)
func namePickerShouldReload() -> Bool

2.4 利用swift編譯器的類型推導機制(寫代碼的時候的東西了這個, 需要移動位置)

充分利用編譯器提供的類型上下文推導機制, 寫更加短小且清晰易懂的代碼.

應該:

let selector = #selector(viewDidLoad)
view.backgroundColor = .red
let toView = context.view(forKey: .to)
let view = UIView(frame: .zero)

不應:

let selector = #selector(ViewController.viewDidLoad)
view.backgroundColor = UIColor.red
let toView = context.view(forKey: UITransitionContextViewKey.to)
let view = UIView(frame: CGRect.zero)

2.5 泛型類型參數(shù)命名規(guī)則

泛型類型參數(shù)名稱應該是有意義的, 且是大寫字母開頭的駝峰命名. 只有當泛型類型參數(shù)沒有確切意義或角色時, 才使用傳統(tǒng)的單個大寫字母命名方式.

應該:

struct Stack<Element> { ... }
func write<Target: OutputStream>(to target: inout Target)
func swap<T>(_ a: inout T, _ b: inout T)

不應:

struct Stack<T> { ... }
func write<target: OutputStream>(to target: inout target)
func swap<Thing>(_ a: inout Thing, _ b: inout Thing)

2.6 關于美式還是英式英語單詞

蘋果公司的API都全部是美式的, 你說你整些英式在里面也不合適吧.

: ]

應該:

let color = "red"

不應:

let colour = "red"

3 代碼組織(還沒有表達清楚, 需要修改)

3.1 extension 的使用

利用 extension 將代碼按照邏輯功能進行組織. 每一個 extension 應該有對應的 //MARK - 注釋來分隔.

比如 UIViewController 的子類代碼中, 可以將 view 的生命期回調(diào), 自定義訪問方法(setter或getter), IBAction等分別放到不同的 extension 中去實現(xiàn).

3.2 協(xié)議的實現(xiàn)

既有繼承關系, 又有協(xié)議(或通俗地說: 接口)實現(xiàn)的情況下, 應將接口的實現(xiàn)放到 extension 中去. 這樣可以保證相關功能的代碼都位于同一片代碼區(qū)域中.

應該:

class MyViewController: UIViewController {
  // class stuff here
}

// MARK: - UITableViewDataSource
extension MyViewController: UITableViewDataSource {
  // table view data source methods
}

// MARK: - UIScrollViewDelegate
extension MyViewController: UIScrollViewDelegate {
  // scroll view delegate methods
}

不應:

class MyViewController: UIViewController, UITableViewDataSource, UIScrollViewDelegate {
  // 所有代碼都被放這里...
}

例外情況:

父類通過某種途徑聲明遵守某協(xié)議后(比如在類定義時聲明遵守協(xié)議, 或是使用 extension 實現(xiàn)協(xié)議), 子類中都無法再次聲明遵守某協(xié)議.

且如果父類中使用 extension 實現(xiàn)了協(xié)議, 子類中是無法重寫任何協(xié)議方法的.(目前不支持重寫 extension 中的方法)

這樣就引出了幾個選擇:

  1. 父類類定義時實現(xiàn)協(xié)議, 子類可以直接重寫協(xié)議方法. 這樣沒有利用任何 extension 的功能.
  2. 父類通過 extension 實現(xiàn)協(xié)議, 則子類中無法對方法進行重寫.
  3. 將協(xié)議放在子類中去實現(xiàn).

總結(jié)上述三點, 目前要利用 extension 來組織協(xié)議的實現(xiàn)代碼的話, 則這個類要么是終端類, 要么其子類沒有重寫協(xié)議方法的需求.

故在繼承鏈的什么位置來實現(xiàn)協(xié)議, 使用何種方式實現(xiàn)協(xié)議, 這些都需要開發(fā)者根據(jù)實際情況來決定了.

3.3 未使用的代碼的處理

對于未使用的(或者是廢棄的)代碼, 包括Xcode自動生成的代碼或者是占位用的注釋等, 都應該移除掉. 當然如果是你需要保留的一些注釋除外, 比如未實現(xiàn)的代碼的注釋等.

另外就是一些自動生成的代碼塊, 實際并沒有做任何工作, 只是調(diào)用父類的實現(xiàn), 這類代碼也應該移除.

應該:

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
  return Database.contacts.count
}

不應:

override func didReceiveMemoryWarning() {
  super.didReceiveMemoryWarning()
  // Dispose of any resources that can be recreated.
}

override func numberOfSections(in tableView: UITableView) -> Int {
  // #warning Incomplete implementation, return the number of sections
  return 1
}

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
  // #warning Incomplete implementation, return the number of rows
  return Database.contacts.count
}

3.4 最小化引用原則

保證代碼中最小限度地引入外部庫. 比如, 當可以只引入 Foundation 就能完成工作的時候, 就不要引入更大的 UIKit 了.

4 空格和縮進

  • 使用兩個空格來代替 tab .(非強制, 討論2個空格還是4個空格沒有任何意義, 唯一的要求是一個公司中必須使用同一種縮進策略, 比如統(tǒng)一2個空格.)
  • 代碼塊的起始大括號, 應和塊開頭的代碼位于同一行. 不要另起一行寫.(拋棄C語言的那一套習慣先)
  • 利用 Xcode 自帶的格式化快捷鍵 control + I 來格式化代碼.

應該:

if user.isHappy {
  // Do something
} else {
  // Do something else
}

不應:

if user.isHappy
{
  // Do something
}
else {
  // Do something else
}
  • 方法與方法之間應該用一個空行隔開.

  • 方法內(nèi)部代碼應該使用空行來對不同邏輯功能的代碼塊進行分隔, 但不可過多, 過多的分隔意味著這個方法可以被再次重構(gòu)分解為多個方法.

  • 冒號的使用原則: 冒號始終靠近左邊, 并且和左邊的詞之間沒有空格, 而右邊則需要一個空格:

    應該:

    class TestDatabase: Database {
      var data: [String: CGFloat] = ["A": 1.2, "B": 3.2]
    }
    

    不應:

    class TestDatabase : Database {
      var data :[String:CGFloat] = ["A" : 1.2, "B":3.2]
    }
    
  • 每行的最大長度應該控制在一個規(guī)定值范圍內(nèi). 而這個值根據(jù)實際需要確定. 暫定120. 可以在Xcode中設置.

  • 避免在行尾出現(xiàn)空白符. (為什么?)

  • 每個文件的末尾添加一個空行. (為什么?)

5 注釋

寫注釋的目的是說明: "為什么這段特定代碼會做這樣的事情".

必須時刻保持注釋與相關代碼同步更新. 所以不能濫用注釋, 但也別不寫注釋. 最好的代碼是自解釋的.

這里所說的注釋指的是代碼注釋, 如果是用于生成文檔的文檔注釋, 則需要詳盡.

6 類和結(jié)構(gòu)

Struct 是值類型的, 故 struct 適用于不需要保持其狀態(tài)的對象. 例如: 一個包含 [啊, 波, 坡] 的數(shù)組和另外一個包含 [啊, 波, 坡] 的數(shù)組, 除了所處存儲空間不同外, 實際上表達的邏輯功能是一樣的, 二者可以隨意互換. 正因為如此, swift 中的 array, string 等等實際都是 struct, 即是值類型的.

Class 是引用類型的. 如果要使用的對象具有一定的特殊性, 并且需要保持其狀態(tài)(即具有一定的生命期), 故需要使用 Class作為該對象的類型. 比如需要建立兩個人的模型, 就需要使用 class 來表達這兩個人, 因為他們兩個是不一樣的, 但是兩個人的生日可以用 struct 來表達, 因為一個2000年1月1日和另外一個2000年1月1日表達的是同一個值.

需要根據(jù)實體的抽象意義, 合理選擇使用值類型還是引用類型.

應該:

class Circle: Shape {
  var x: Int, y: Int
  var radius: Double
  var diameter: Double {
    get {
      return radius * 2
    }
    set {
      radius = newValue / 2
    }
  }

  init(x: Int, y: Int, radius: Double) {
    self.x = x
    self.y = y
    self.radius = radius
  }

  convenience init(x: Int, y: Int, diameter: Double) {
    self.init(x: x, y: y, radius: diameter / 2)
  }

  override func area() -> Double {
    return Double.pi * radius * radius
  }
}

extension Circle: CustomStringConvertible {
  var description: String {
    return "center = \(centerString) area = \(area())"
  }
  private var centerString: String {
    return "(\(x),\(y))"
  }
}

6.1 self的使用

不是必須的情況下, 盡量省略self.

6.2 計算屬性

當寫只讀屬性的 getter 時, 應省略 get塊:

應該:

var diameter: Double {
  return radius * 2
}

不應:

var diameter: Double {
  get {
    return radius * 2
  }
}

6.3 合理使用 final 關鍵字

7 閉包表達式

只有當閉包是方法的最后一個參數(shù)時, 才考慮寫尾隨閉包.

盡量給閉包中的參數(shù)賦予一個具體名稱來表達其含義.

應該:

UIView.animate(withDuration: 1.0) {
  self.myView.alpha = 0
}

UIView.animate(withDuration: 1.0, animations: {
  self.myView.alpha = 0
}, completion: { finished in
  self.myView.removeFromSuperview()
})

不應:

UIView.animate(withDuration: 1.0, animations: {
  self.myView.alpha = 0
})

UIView.animate(withDuration: 1.0, animations: {
  self.myView.alpha = 0
}) { f in
  self.myView.removeFromSuperview()
}

當上下文意思清晰的情況下, 可以省略單行閉包中的return:

attendeeList.sort { a, b in
  a > b
}

另外就是閉包的一個格式問題, 由開發(fā)者按實際情況決定:

let value = numbers.map { $0 * 2 }.filter { $0 % 3 == 0 }.index(of: 90)

let value = numbers
  .map {$0 * 2}
  .filter {$0 > 50}
  .map {$0 + 10}

8 類型

應盡可能使用 swift 中的原生類型.

應該:

let width = 120.0                                    // Double
let widthString = (width as NSNumber).stringValue    // String

不應:

let width: NSNumber = 120.0                          // NSNumber
let widthString: NSString = width.stringValue        // NSString

只有當對性能改善更加明顯的情況下, 才考慮使用 OC 中的類型.(比如在 Sprite Kit 中使用 CGFloat)

8.1 常量

如果一個量的值不會發(fā)生變化的情況下, 應使用 let 聲明這個量, 而不是 var.

小貼士: 將所有的量都先用 let 聲明, 只有當編譯器發(fā)出警告時, 才替換為 var.

另外就是應盡量將所有使用到的常量按照功能不同放置在不同名字空間中(如enum).

應該:

enum Math {
  static let e = 2.718281828459045235360287
  static let root2 = 1.41421356237309504880168872
}

let hypotenuse = side * Math.root2

不應:

let e = 2.718281828459045235360287  // pollutes global namespace
let root2 = 1.41421356237309504880168872

let hypotenuse = side * root2 // what is root2?

上面的 enum 中沒有 case, 這樣的好處是讓其僅僅作為一個名字空間使用.

8.2 類方法和類屬性

類方法和類屬性的作用類似于全局變量, 不過由于它們處于某些名字空間下, 更加合理安全.

8.3 可選類型

當方法或函數(shù)的返回值可能不存在時, 則將返回值類型聲明為可選類型.

只有當確定可選值在當前時刻之前的確會存在的情況下, 才考慮用隱式可選類型 !.

當值只會被訪問一次的情況下, 使用可選鏈來獲取這個值:

self.textContainer?.textLabel?.setNeedsDisplay()

當值會被多次用到時, 則使用可選綁定:

if let textContainer = self.textContainer {
  // do many things with textContainer
}

由于在類型中已經(jīng)隱式說明了變量是可選類型的, 故在命名時盡量不要使用 optionalString, maybeView這樣形式的名字.

在使用可選綁定的時候, 盡量使用名字覆蓋的辦法, 不要再次將解包后的變量命名為諸如 unwrappedXXX 的形式.

應該:

var subview: UIView?
var volume: Double?

// later on...
if let subview = subview, let volume = volume {
  // do something with unwrapped subview and volume
}

不應:

var optionalSubview: UIView?
var volume: Double?

if let unwrappedSubview = optionalSubview {
  if let realVolume = volume {
    // do something with unwrappedSubview and realVolume
  }
}

8.4 懶加載

利用懶加載, 可以精確控制一個變量的生命期.

實現(xiàn)的時候可以使用一個直接執(zhí)行的閉包 { }() 或一個私有工廠方法進行對象創(chuàng)建, swift 會在使用到這個對象的時候才執(zhí)行那個閉包或者調(diào)用私有工廠方法.

lazy var locationManager: CLLocationManager = self.makeLocationManager()

private func makeLocationManager() -> CLLocationManager {
  let manager = CLLocationManager()
  manager.desiredAccuracy = kCLLocationAccuracyBest
  manager.delegate = self
  manager.requestAlwaysAuthorization()
  return manager
}

注意:

  • 利用閉包實現(xiàn)懶加載時, 不需要 [unowned self], 因為這里不會出現(xiàn)引用循環(huán).
  • 上述代碼中的 locationManager 首次創(chuàng)建的時候會請求用戶權(quán)限, 所以這里使用懶加載來加載它是非常合適的.

8.5 類型推導

盡量利用類型推導來寫更加短小簡潔的代碼. 只有當類型推導的默認類型不滿足要求時, 才考慮顯式指定類型. 另外就是對于短小的數(shù)組, 盡量直接使用數(shù)組的字面量來表達數(shù)組.

應該:

let message = "Click the button"
let currentBounds = computeViewBounds()
var names = ["Mic", "Sam", "Christine"]
let maximumWidth: CGFloat = 106.5

不應:

let message: String = "Click the button"
let currentBounds: CGRect = computeViewBounds()
let names = [String]()

8.5.1 空數(shù)組或字典的類型標識

如果新建空數(shù)組或字典供之后使用, 則應該使用類型標識.(另外如果字典或數(shù)組字面量表達式過長時, 也可以考慮添加類型標識)

應該:

var names: [String] = []
var lookup: [String: Int] = [:]

不應:

var names = [String]()
var lookup = [String: Int]()

8.5.2 類型標識的寫法

盡量使用 swift 的語法糖來寫類型標識, 而不要去用原始的冗長方式.

應該:

var deviceModels: [String]
var employees: [Int: String]
var faxNumber: Int?

不應:

var deviceModels: Array<String>
var employees: Dictionary<Int, String>
var faxNumber: Optional<Int>

9 函數(shù)和方法之間的選擇

只有當無法將這個功能歸入某個類型或子名字空間內(nèi)時, 才考慮使用函數(shù).

let tuples = zip(a, b)  // feels natural as a free function (symmetry)
let value = max(x, y, z)  // another free function that feels natural

其余的情況都應該將這些功能作為某個類型的類方法或?qū)ο蠓椒?

應該:

let sorted = items.mergeSorted()  // easily discoverable
rocket.launch()  // acts on the model

不應:

let sorted = mergeSort(items)  // hard to discover
launch(&rocket)

10 內(nèi)存管理

內(nèi)存管理進入半自動時代, 所以唯一要記住的原則是: 不要制造引用循環(huán)!

在可能出現(xiàn)循環(huán)引用的情況下, 將變量類型標記為weakunowned. 另外, 也可以使用值類型 structenum 來避免引用循環(huán).(為什么? 這些對象的存儲空間還是在堆內(nèi)存中, 只是指針變量是放在棧中的)

10.1 閉包中的self

當在閉包中需要使用 self, 且會形成引用循環(huán)時, 考慮使用 weak 標記 self, 盡量不要使用 unowned, 除非 self 在執(zhí)行這個閉包時很明顯是還存在的情況.

應結(jié)合 guard 來安全地使用 weak self.

應該:

resource.request().onComplete { [weak self] response in
  guard let strongSelf = self else { 
    return 
  }
  let model = strongSelf.updateModel(response)
  strongSelf.updateUI(model)
}

不應:

// might crash if self is released before response returns
resource.request().onComplete { [unowned self] response in
  let model = self.updateModel(response)
  self.updateUI(model)
}

也不應:

// deallocate could happen between updating the model and updating UI
resource.request().onComplete { [weak self] response in
  let model = self?.updateModel(response)
  self?.updateUI(model)
}

11 訪問控制

合理使用 privatefileprivate, 這樣代碼會更加清晰, 且提高了封裝的質(zhì)量. 一般來說, 能用 private 的地方盡量用它. 但如果某些成分需要要 extension 中使用的時候, 則需要使用 fileprivate.

另外的 open, publicinternal, 就需要按情況來使用了.

訪問控制修飾符應該放在最開始的位置. 除了有 static 以及注解的時候.

應該:

private let message = "Great Scott!"

class TimeMachine {  
  fileprivate dynamic lazy var fluxCapacitor = FluxCapacitor()
}

不應:

fileprivate let message = "Great Scott!"

class TimeMachine {  
  lazy dynamic fileprivate var fluxCapacitor = FluxCapacitor()
}

12 流程控制

能夠使用 for-in 的時候就不要用 while 方式的循環(huán).

應該:

for _ in 0..<3 {
  print("Hello three times")
}

for (index, person) in attendeeList.enumerated() {
  print("\(person) is at position #\(index)")
}

for index in stride(from: 0, to: items.count, by: 2) {
  print(index)
}

for index in (0...3).reversed() {
  print(index)
}

不應:

var i = 0
while i < 3 {
  print("Hello three times")
  i += 1
}

var i = 0
while i < attendeeList.count {
  let person = attendeeList[i]
  print("\(person) is at position #\(i)")
  i += 1
}

13 最佳側(cè)原則

當編寫條件判斷代碼的時候, 整個代碼對齊的左側(cè)稱為"最佳側(cè)", 意思是如果代碼越遠離左側(cè), 表示嵌套的層次越深, 代碼的質(zhì)量也就越低. 當有多層嵌套的時候, 盡量使用 guard 來簡化嵌套.

應該:

func computeFFT(context: Context?, inputData: InputData?) throws -> Frequencies {

  guard let context = context else {
    throw FFTError.noContext
  }
  guard let inputData = inputData else {
    throw FFTError.noInputData
  }

  // use context and input to compute the frequencies
  return frequencies
}

不應:

func computeFFT(context: Context?, inputData: InputData?) throws -> Frequencies {

  if let context = context {
    if let inputData = inputData {
      // use context and input to compute the frequencies

      return frequencies
    } else {
      throw FFTError.noInputData
    }
  } else {
    throw FFTError.noContext
  }
}

另外就是 guard 后面可以寫多條可選綁定語句, 這樣寫也可以簡化很多嵌套代碼.

應該:

guard let number1 = number1,
      let number2 = number2,
      let number3 = number3 else {
  fatalError("impossible")
}
// do something with numbers

不應:

if let number1 = number1 {
  if let number2 = number2 {
    if let number3 = number3 {
      // do something with numbers
    } else {
      fatalError("impossible")
    }
  } else {
    fatalError("impossible")
  }
} else {
  fatalError("impossible")
}

13.1 guard 中失敗的處理

在 guard 后的 else 語句中寫的一般是某種形式的退出代碼, 且一般都是單行代碼如 return, throw, break, continue或者 fatalError() 等.

在實際編碼的時候, 盡量避免在里面寫大段的代碼. 如果真的需要寫一些清理功能的代碼, 則可以放到 defer 中去寫, 而不是在 guardelse 塊中.

14 分號的使用

swift 不強制使用分號, 且一般應該不去寫表達式末尾的分號. 只有當想在一行寫多條語句的時候, 語句間才用分號分隔.

但請記住: 不應將多條語句寫在一行上, 不應在表達式末尾添加分號.

不要把 swift 當做一種簡單的腳本語言看待.

應該:

let swift = "not a scripting language"

不應:

let swift = "not a scripting language";

15 括號的使用

盡量避免在條件語句中使用括號. 只有當語句比較復雜的時候, 才考慮用括號來組織.

應該:

if name == "Hello" {
  print("World")
}
let playerMark = (player == current ? "X" : "O")

不應:

if (name == "Hello") {
  print("World")
}

16 Xcode中的組織名稱以及 Bundle ID 的命名(可選)

Xcode 中的組織名稱(organization)需要符合英文書寫習慣, 即名字首字母大寫, 各單詞用空格分開, 比如 Ray Wenderlich.

Bundle ID 需要設置為如 com.ray.TutorialName 的形式, 其中 TutorialName 即為工程名稱.

17 版權(quán)聲明的寫法

版權(quán)聲明需要在每個源文件的開頭都寫上. 這個就各有不同了.

下面是 MIT 開源協(xié)議的版權(quán)聲明文本模板, 僅作為參考.

    /**
     * Copyright (c) 2017 XXXXX公司 LLC
     *
     * Permission is hereby granted, free of charge, to any person obtaining a copy
     * of this software and associated documentation files (the "Software"), to deal
     * in the Software without restriction, including without limitation the rights
     * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     * copies of the Software, and to permit persons to whom the Software is
     * furnished to do so, subject to the following conditions:
     *
     * The above copyright notice and this permission notice shall be included in
     * all copies or substantial portions of the Software.
     *
     * Notwithstanding the foregoing, you may not use, copy, modify, merge, publish, 
     * distribute, sublicense, create a derivative work, and/or sell copies of the 
     * Software in any work that is designed, intended, or marketed for pedagogical or 
     * instructional purposes related to programming, coding, application development, 
     * or information technology.  Permission for such use, copying, modification,
     * merger, publication, distribution, sublicensing, creation of derivative works, 
     * or sale is expressly withheld.
     *
     * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     * THE SOFTWARE.
     */

18 對待生活的態(tài)度

保持樂觀積極的態(tài)度, 笑也要開心地笑:

應該:

:]      //這個是開心笑

不應:

:)      //這個是勉強笑
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市沛贪,隨后出現(xiàn)的幾起案子震叙,更是在濱河造成了極大的恐慌苞俘,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,482評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件乡翅,死亡現(xiàn)場離奇詭異珠插,居然都是意外死亡奴迅,警方通過查閱死者的電腦和手機材义,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評論 2 382
  • 文/潘曉璐 我一進店門均抽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人其掂,你說我怎么就攤上這事油挥。” “怎么了清寇?”我有些...
    開封第一講書人閱讀 152,762評論 0 342
  • 文/不壞的土叔 我叫張陵喘漏,是天一觀的道長。 經(jīng)常有香客問我华烟,道長翩迈,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,273評論 1 279
  • 正文 為了忘掉前任盔夜,我火速辦了婚禮负饲,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘喂链。我一直安慰自己返十,他們只是感情好,可當我...
    茶點故事閱讀 64,289評論 5 373
  • 文/花漫 我一把揭開白布椭微。 她就那樣靜靜地躺著洞坑,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蝇率。 梳的紋絲不亂的頭發(fā)上迟杂,一...
    開封第一講書人閱讀 49,046評論 1 285
  • 那天,我揣著相機與錄音本慕,去河邊找鬼排拷。 笑死,一個胖子當著我的面吹牛锅尘,可吹牛的內(nèi)容都是我干的监氢。 我是一名探鬼主播,決...
    沈念sama閱讀 38,351評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼藤违,長吁一口氣:“原來是場噩夢啊……” “哼浪腐!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起顿乒,我...
    開封第一講書人閱讀 36,988評論 0 259
  • 序言:老撾萬榮一對情侶失蹤议街,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后淆游,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體傍睹,經(jīng)...
    沈念sama閱讀 43,476評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,948評論 2 324
  • 正文 我和宋清朗相戀三年犹菱,在試婚紗的時候發(fā)現(xiàn)自己被綠了拾稳。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,064評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡腊脱,死狀恐怖访得,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情陕凹,我是刑警寧澤悍抑,帶...
    沈念sama閱讀 33,712評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站杜耙,受9級特大地震影響搜骡,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜佑女,卻給世界環(huán)境...
    茶點故事閱讀 39,261評論 3 307
  • 文/蒙蒙 一记靡、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧团驱,春花似錦摸吠、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至紊选,卻和暖如春啼止,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背丛楚。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評論 1 262
  • 我被黑心中介騙來泰國打工族壳, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人趣些。 一個月前我還...
    沈念sama閱讀 45,511評論 2 354
  • 正文 我出身青樓仿荆,卻偏偏與公主長得像,于是被迫代替她去往敵國和親坏平。 傳聞我的和親對象是個殘疾皇子拢操,可洞房花燭夜當晚...
    茶點故事閱讀 42,802評論 2 345

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