56

Swift らしいコードを目指そう #eventdots

Embed Size (px)

Citation preview

1 / 7

// 定義は、外部引数名、内部変数名、型名を活用して紡ぐ func insert(_ newItem: Item, into position: Int)

// 使用時は、変数名も活用して紡ぐ bookshelf.insert(newBook, into: freeSpace)

// item が冗長だったり、freeSpace が説明不足だったり bookshelf.insert(item: newBook, position: freeSpace)

// 定義を見れば、意図を汲めるけれど… func add(handler: () -> Void, for eventName: String)

// 使用時に、説明不足で主体から用途が想像しにくい document.add(handler: () -> Void, for: String)

// 定義時に名前で補足すると… func addEventHandler(_ handler: () -> Void, forEventName name: String)

// 使用時に用途を汲みやすくなる document.addEventHandler(handler: () -> Void,

forEventName: String)

// 動詞系で、自身を書き換えないなら、末尾に“ed”とか nonmutating func advanced(by n: Int) -> Int

// 動詞系で、自身を書き換えないなら、末尾に“ing”とか nonmutating func adding(_ other: Int) -> Int

// 動詞系で、自身を書き換えるなら、動詞そのもの mutating func add(_ other: Int)

// 名詞系で、自身を書き換えないなら、名詞そのもの nonmutating func squareRoot() -> Double

// 名詞系で、自身を書き換えるなら、先頭に“form”付与 mutating func formSquareRoot()

// 引数を書き換える場合も Mutating と同じく“form”付与 nonmutating func formIndex(after i: inout Int)

// 素直に命名するとラベルがアンバランスになる func cell(atColumn: Int, row: Int) -> Cell

// at をメソッド名に含めることでラベルが整う func cellAt(column: Int, row: Int) -> Cell

// タプルで表現することでもバランスが取れる func cell(at location: (column:Int, row:Int)) -> Cell

2 / 7

// bytes と count をとって初期化する init(bytes: UnsafeRawPointer, count: Int)

// value と radix と uppercase をとって初期化する init(_ value: Int, radix: Int, uppercase: Bool)

// lower と upper をとって初期化する init(lower: Bound, upper: Bound)

// Int 型の値を String 型で忠実に再現(全幅変換) struct String { init(_ value: Int, radix: Int = 10) }

// UInt32 型の値をビットパターンとして Int32 型に再解釈 struct Int32 { init(truncatingBitPattern pattern: UInt64) }

// Int 型の値を String 型にキャスト(全幅変換) let string = String(number, radix: 16)

// ビットパターンを指定して Int32 型を生成(Narrow 変換) let value = Int32(truncatingBitPattern: number)

// 範囲を生成 let range = MyRange(lower: start, upper: last)

3 / 7

// 自作の型なら、直接でも拡張でも自由に備えられる struct Bookshelf : Collection {

mutating func arrange() { … } }

// 他者が作ったものにも、拡張で備えられる extension Collection where Iterator.Element == Book {

func sortedByTitle() -> [Book] { … } }

// 全ての値が対等で、主体が定まらない func average(of values: Double...) -> Double

// 具体的な主体が定義に現れないため、所属できない func convert<T: Any, U: Compatible>(from: T) -> U

// プログラミングの分野では、絶対値は関数 abs で取得する func abs(_ x: Double) -> Double

4 / 7

struct Int128 {

fileprivate var low: UInt64 fileprivate var high: UInt64

// Int 型の値を Int128 型に全幅変換 init(_ value: Int) {

low = UInt64(value) high = 0 } }

extension Int {

// Int128 型の値を Int 型に全幅変換 init(_ value: Int128) {

guard value.high == 0 else { fatalError("Overflow") }

self = Int(value.low) } }

// お馴染みの Double から Int へのキャスト例 let taxIncluded = Int(Double(price) * (1 + tax))

// お馴染みのキャストと同じ書き方になる let endOfInteger = Int128(Int64.max) + 1

// 自作の Int128 から Int への変換もいつも通り let stride = Int(Int128.max / samples)

5 / 7

// 標準ライブラリーに規定されている性質

/// A type that can be compared for value equality. protocol Equatable {

/// Returns a Boolean value indicating /// whether two values are equal. static func ==(lhs: Self, rhs: Self) -> Bool }

// プロトコルで比較可能性を説明すると… extension Int128 : Equatable {

static func == (lhs: Int128, rhs: Int128) -> Bool {

return (lhs.low, lhs.high) == (rhs.low, rhs.high) } }

// 比較演算を使って比較可能になる Int128(1000) == Int128(1000) Int128(1000) != Int128(1000)

// 比較可能な要素を扱う場合だけ使えるようになっている extension Array where Element : Equatable {

func index(of element: Element) -> Int? }

// 配列で、要素からインデックスを特定できるようになる let values = [Int128(1), Int128(5), Int128(10)]

let index = values.index(of: Int128(5))

6 / 7

// 標準ライブラリーに規定されている性質

/// A type with a customized textual representation. protocol CustomStringConvertible {

/// A textual representation of this instance. var description: String { get } }

enum Device : CustomStringConvertible {

case iPhone, iPad, appleWatch

var description: String {

switch self { case .iPhone: return "iPhone" case .iPad: return "iPad" case .appleWatch: return " Watch" } }

let device = Device.appleWatch

// テキスト表現への Narrow 変換 let displayText = String(describing: device)

// テキスト表現に変換して、テキストコンソールに出力 print(device)

// String 型の文字列補完構文は、テキスト表現を使用 let message = "I love \(device)"

7 / 7

// 変数 floatValues が Array<Float> で定義されている let floatValues: [Float]

// サブスクリプトに範囲を渡すと、部分配列が取れる let slice = floatValues[2 ..< 6]

// 部分配列の型は ArraySlice<Float> になる type(of: slice) == ArraySlice<Float>.self

// 一般的な定義の仕方 func sum(of values: [Double]) -> Double {

return values.reduce(0, +) }

// Float 型の配列の部分配列の合計を計算 sum(of: floatValues[2 ..< 6].map(Double.init))

// 任意の浮動小数点数を対象にする func sum<T: FloatingPoint>(of values: [T]) -> T {

return values.reduce(0, +) }

// Float 型の配列の部分配列の合計を計算 sum(of: Array(floatValues[2 ..< 6]))

// 標準ライブラリーに規定されている性質

/// A type that provides sequential, /// iterated access to its elements. public protocol Sequence {

/// A type that provides the sequence's iteration /// interface and encapsulates its iteration state. associatedtype Iterator : IteratorProtocol

// 連続する任意の浮動小数点数を対象にする func sum<S: Sequence, T: FloatingPoint> (of values: S) -> T where S.Iterator.Element == T {

return values.reduce(0, +) }

// 連続する浮動小数点数の部分配列の合計を計算 sum(of: floatValues[2 ..< 6])

// 自身の値でストライドできる値を対象にする func sum<S: Sequence, T:Strideable>(of values: S) -> T where S.Iterator.Element == T, T.Stride == T {

return values.reduce(0) { $0.advanced(by: $1) } }

// 連続する値の部分配列の合計を計算 sum(of: floatValues[2 ..< 6]) sum(of: integerValues[2 ..< 6])

// 整数を対象とした合計関数 func sum<S:Sequence, T:Integer>(of values:S) -> T where S.Iterator.Element == T { return values.reduce(0, +) }

// 浮動小数点数を対象とした合計関数 func sum<S:Sequence, T:FloatingPoint>(of values:S) -> T where S.Iterator.Element == T { return values.reduce(0, +) }