はじめに
数値計算を総称的に扱うためのNumeric Protocolみたいなのないの?
→Swift5からあるらしいで。
それを知らなくて自分で考えてた話です。
- 当初似たようなことやってる人がいるだろうと思って探してみるも
見つけたものには、以下のような制約があった。 - それの制約を取り払えないか? というところからのスタート。
A
Swift5の標準に基づく実装と自前実装
Swift5の標準に基づく実装
まずは正しい(と思っている)答え
standard
extension Sequence where Element:AdditiveArithmetic {
func sum() -> Element {
return reduce(.zero, +)
}
}
AdditiveArithmeticとは…
基本の数値型(Int、Doubleなど)で実装済みのプロトコル。(Swift5から)
zero(初期値)と加減算オペレータが定義されている
standard
protocol AdditiveArithmetic {
static var zero: Self
static func + (Self, Self) -> Self
static func += (Self, Self)
static func - (Self, Self) -> Self
static func -= (Self, Self)
}
標準実装があるのを知らなくて自分で定義したプロトコルと実装。
要らないんですが考えの過程を残すために載せておきます。
my_implementation
protocol Summable{
init()
static func +(lhs: Self, rhs: Self) -> Self
}
extension Int:Summable{}
extension Int64:Summable{}
extension String:Summable{}
// any more
extension Sequence where Element:Summable {
func sum<T:Summable>() -> Element where Element==T {
return reduce(T.init(), +)
}
}
// use eg
print( [1,2,3].sum() ) // …6
print( ["1","2","3"].sum() ) // …"123"
実装にあたり悩んだところ。
- protocolはclassとは異なる要領で総称型に対する処理を実現している。
- class …
Class<T>
の要領で総称型(ジェネリクス)を定義して利用 (struct、関数も同様) - protocol … プロパティで総称型として扱いたい型情報を管理(associatedtype)
- 扱いが異なる理由 … なぜSwiftのプロトコルはジェネリクスをサポートしないのか
- 「
extension ExtProtocol where AssoociatedType:MyProtocl
のwhere
は拡張対象を絞るだけであり、AssociateTypeを決定しているわけではない。protocolに対して汎用処理を実現したい場合、各関数に対してジェネリクス<T>
をT == AssociateType
だとして定義しなければ定まらない。」ことが最初理解できなかった。 - 合計値計算の基準となる初期値(数値であれば、各型のゼロ)をどのように定義するか。
-
reduce
の第一引数に型を指定た初期値を与える必要がある。(異なる型同士は加算できないため) - 利用時の記述を楽にしたい。※
-
init()
で初期値が取得でき、楽ができた。
※利用時にこんな風に{}内の記述したくない
extension Double:Summable{
static var zero:Self { return Double(0)}
}
//protocol Summable{
// static func +(lhs: Self, rhs: Self) -> Self
// static var zero:Self{get}
//}