こんにちは!
普段iOSではSwiftを、Androidやサーバー側の開発ではScalaを利用して開発をしています。
どちらも微妙に似ていて、けれど、やはり違っているので、
たまにSwiftならこう書けるのに、とか、Scalaならこう書けるのに、と思うことがあります。
なので、SwiftのOptionalをScalaっぽく扱えるように拡張してみました。
ScalikeOptional.swift
ワンライナー縛りで書いています。
GitHubにあげました
https://github.com/iTerasaka/ScalikeOptional.swift
// MARK: - ScalikeOptional.swift
extension Optional {
static func empty() -> Wrapped? {
return Optional<Wrapped>.None
}
public var get: Wrapped {
return self!
}
public var isEmpty: Bool {
return self.map { _ in false } ?? true
}
public var isDefined: Bool {
return !self.isEmpty
}
public func getOrElse(p: Wrapped) -> Wrapped {
return self ?? p
}
public func orElse(p: Wrapped) -> Wrapped? {
return Optional(self ?? p)
}
public func forEach(@noescape f: Wrapped -> Void) -> Void {
if let some = self { f(some) }
}
public func forAll(@noescape f: Wrapped -> Bool) -> Bool {
return self.map(f) ?? true
}
public func fold<A>(ifEmpty: A, @noescape _ f: Wrapped -> A) -> A {
return self.map(f) ?? ifEmpty
}
public func exists(@noescape p: Wrapped -> Bool) -> Bool {
return self.map(f) ?? false
}
public func collect<A, B>(@noescape f: A -> B) -> B? {
return (self as? A).map(f) ?? nil
}
public func filter(@noescape p: Wrapped -> Bool) -> Wrapped? {
return self.exists(p) ? self : nil
}
}
試してみる
// MARK: - prepare
var str: String? = "hoge"
var strOpt: String? = nil
// MARK: - property
str.get // "hoge"
strOpt.get // throw Error
str.isEmpty // false
strOpt.isEmpty // true
str.isDefined // true
strOpt.isDefined // false
strOpt.getOrElse("空です") // "hoge"
strOpt.getOrElse("空です") // "空です"
strOpt.orElse("空です") // Optional("hoge")
strOpt.orElse("空です") // Optional("空です")
// MARK: - forEach
str.forEach { print("\($0)がはいっています") } // print(hogeがはいっています)
strOpt.forEach { print("\($0)がはいっています") } // なにもしない
// MARK: - forAll
str.forAll { $0 == "h" } // false
str.forAll { $0 == "hoge" } // true
strOpt.forAll { $0 == "hoge" } // true
// MARK: - exists
str.exists { $0 == "h" } // false
str.exists { $0 == "hoge" } // true
// MARK: - fold
str.fold(false) { return $0 == "hoge" } // true
str.fold(false) { return $0 == "h" } // false
strOpt.fold(false) { return $0 == "hoge" } // false
strOpt.fold(false) { return $0 == "h" } // false
// MARK: - collect
str.collect { (a:String) in return a + "がはいっています" } // hogeがはいっています
strOpt.collect { (a:String) in return a + "1" } // nil
str.collect { (a:Int) in return a + 1 } // nil
strOpt.collect { (a:String) in return a + "1" } // nil
// MARK: - filter
str.filter { $0 == "hoge" } // Optional(hoge)
str.filter { $0 == "aaa" } // nil
結論
Optional便利ですねー