Swiftでジェネリックとカスタム演算子をいじっているときに、この問題に遭遇しました。以下のコード スニペットでは、2 つの新しい前置演算子 ∑ と ∏ を導入し、それぞれの前置関数をベクトル和と積として実装しています。すべての整数型と浮動小数点型に対してこれらの関数や同様の関数を個別に実装する必要がないように、代わりに 2 つのプロトコルを定義しました: Summable (+ 実装が必要) と Multiplicable (* 実装が必要) です。また、たとえば Array 型と Rage 型で機能する SequenceType 引数用の 2 つの関数を実装しました。最後に、スニペットの最後にある println 呼び出しから、∏(1...100) を除いて、これがすべてうまく機能していることがわかります。ここで、プログラムは EXC_BAD_INSTRUCTION でクラッシュし、他に何もありません。∑(1...100) が機能することに注意してください。同じように実装されていても。実際、行の初期値を変更するとreturn reduce(s, 1, {$0 * $1})
∏への呼び出しからの出力が間違っているにもかかわらず、プログラムがエラーなしで完了するよりも 0 にします。
要するに初期値を0か1にするってこと!? 問題のある行のコードを数行にわたって展開すると、クラッシュが で発生していることが明らかになり$0 * $1
ます。また、クロージャ{$0 * $1}
と{$0 + $1}
I の代わりに、 + および * 演算子関数を直接渡すことができる必要があることにも注意してください。残念ながら、これはコンパイラを怒らせます:「ジェネリックメソッドの部分的な適用は許可されていません」。
何か案は?1 (またはゼロ以外の任意の Int) を 0 に交換すると、どのようにクラッシュする可能性がありますか? また、これが乗算の範囲でのみ発生するのに、初期値が 0 または 1 の加算の範囲は正常に機能するのはなぜですか?
prefix operator ∑ {}
prefix operator ∏ {}
protocol Summable { func +(lhs: Self, rhs: Self) -> Self }
protocol Multiplicable { func *(lhs: Self, rhs: Self) -> Self }
extension Int: Summable, Multiplicable {}
extension Double: Summable, Multiplicable {}
prefix func ∑<T, S: SequenceType where T == S.Generator.Element,
T: protocol<IntegerLiteralConvertible, Summable>>(var s: S) -> T {
return reduce(s, 0, {$0 + $1})
}
prefix func ∏<T, S: SequenceType where T == S.Generator.Element,
T: protocol<IntegerLiteralConvertible, Multiplicable>>(var s: S) -> T {
return reduce(s, 1, {$0 * $1})
}
let ints = [1, 2, 3, 4]
let doubles: [Double] = [1, 2, 3, 4]
println("∑ints = \( ∑ints )") // --> ∑ints = 10
println("∑doubles = \( ∑doubles )") // --> ∑doubles = 10.0
println("∑(1...100) = \( ∑(1...100) )") // --> ∑(1...100) = 5050
println("∏ints = \( ∏ints )") // --> ∏ints = 24
println("∏doubles = \( ∏doubles )") // --> ∏doubles = 24.0
println("∏(1...100) = \( ∏(1...100) )") // --> CRASH: EXC_BAD_INSTRUCTION
編集:私にとってはかなり恥ずかしいことですが、このコードで私が犯しているエラーは、プログラミングの目のかわいいテストになります。以下のMartinの回答を読む前に、それを理解できるかどうかを確認してください. そうするとき、あなたは自分自身について気分が良くなるでしょう。(ただし、別のキャリアを探す必要があるかもしれません。)