web-dev-qa-db-ja.com

マイナス記号「-」は通常、プラス記号と同じ方法でオーバーロードされないのはなぜですか?

プラス記号+は加算と文字列連結に使用されますが、そのコンパニオン:マイナス記号-は、文字列のトリミングや、減算以外の場合には一般的に見られません。その理由や制限は何でしょうか?

JavaScriptの次の例を考えてみます。

var a = "abcdefg";
var b = "efg";

a-b == NaN
// but
a+b == "abcdefgefg"
65
Digvijay Yadav

要するに、人々がアルゴリズムを書きたかった文字列に対して、特に有用な減算のような演算はありません。

+演算子は、一般に、加算 monoid の演算、つまり、identity要素との連想演算を示します。

  • A +(B + C)=(A + B)+ C
  • A + 0 = 0 + A = A

整数の加算、文字列の連結、和集合などのすべてに同じ代数構造を持っているため、この演算子を使用することは理にかなっています。

1 + (2 + 3) == (1 + 2) + 3
1 + 0 == 0 + 1 == 1

"a" + ("b" + "c") == ("a" + "b") + "c"
"a" + "" == "" + "a" == "a"

そして、それを使用して、「連結可能」なもののシーケンスで機能するconcat関数のような便利なアルゴリズムを書くことができます。例えば:

def concat(sequence):
    return sequence.reduce(+, 0)

減算-が関係する場合、通常は group の構造について話します。これはinverseを追加します-すべての要素AのAなので、次のようになります。

  • A + −A = −A + A = 0

そして、これは整数や浮動小数点の減算、さらにはセットの差のようなものには意味がありますが、文字列やリストにはそれほど意味がありません。 "foo"の逆は何ですか?

cancellative monoid と呼ばれる構造があり、逆はありませんが、cancellationプロパティがあります。 :

  • A − A = 0
  • A − 0 = A
  • (A + B)− B = A

これは記述した構造であり、"ab" - "b" == "a"ですが、"ab" - "c"は定義されていません。この構造を使用する便利なアルゴリズムが多くないだけです。連結をシリアライゼーションと考えると、減算をある種の解析に使用できると思います。

116
Jon Purdy

2つの有効な文字列の連結は常に有効な操作ですが、その逆は当てはまりません。

var a = "Hello";
var b = "World";

どうしたら良い a - b ここに?質問自体が無効であるため、その質問に答える良い方法はありません。

37
Mason Wheeler

文字列操作の_-_演算子には十分な「セマンティックコヒージョン」がないためです。演算子は、そのオーバーロードがそのオペランドに対して何を行うかが完全に明確であり、文字列の減算がそのバーを満たさない場合にのみ、オーバーロードする必要があります。

したがって、メソッド呼び出しが推奨されます。

_public string Remove(string source, string toRemove)
public string Replace(string source, string oldValue, string newValue)
_

C#言語では、文字列の連結に_+_を使用します。

_var result = string1 + string2 + string3;
_

の代わりに

_var result = string.Concat(string1, string2, string3);
_

セマンティックの観点からは、関数呼び出しの方がおそらく「正しい」とはいえ、便利であり、間違いなく読みやすくなっています。

_+_演算子が実際に意味するのは、このコンテキストでは1つだけです。これは、_-_には当てはまりません。文字列を減算するという概念はあいまいです(newValueパラメータとして_""_を使用した関数呼び出しReplace(source, oldValue, newValue)は、すべての疑いを取り除きます、および関数を使用して、部分文字列を削除するだけでなく、変更することもできます)。

もちろん、問題は、演算子のオーバーロードが演算子に渡される型に依存することであり、数値が本来あるはずの場所に文字列を渡すと、予期しない結果になる可能性があります。さらに、多くの連結(つまり、ループ内)では、StringBuilderオブジェクトが望ましいです。これは、_+_を使用するたびに新しい文字列が作成され、パフォーマンスが低下する可能性があるためです。したがって、_+_演算子は、すべてのコンテキストで適切であるとは限りません。

文字列の連結に対して_+_演算子よりも意味的なまとまりのある演算子のオーバーロードがあります。これは、2つの複素数を加算するものです。

_public static Complex operator +(Complex c1, Complex c2) 
{
    return new Complex(c1.real + c2.real, c1.imaginary + c2.imaginary);
}
_
28
Robert Harvey

Groovy言語-を許可します:

println('ABC'-'B')

戻り値:

AC

そして:

println( 'Hello' - 'World' )

戻り値:

Hello

そして:

println('ABABABABAB' - 'B')

戻り値:

AABABABAB
8
Wim Deblauwe

プラス記号はおそらく多くの場合状況に応じて意味がありますが、Pythonの反例(おそらくルールを証明する例外)は-を提供するセットオブジェクトですが、 +ではない:

>>> set('abc') - set('bcd')
set(['a'])
>>> set('abc') + set('bcd')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'set' and 'set'

+記号を使用しても意味が曖昧になる可能性があるため、意味がありません。これは集合交差または和集合を意味しますか?代わりに、ユニオンには|を使用し、交差には&を使用します。

>>> set('abc') | set('bcd')
set(['a', 'c', 'b', 'd'])
>>> set('abc') & set('bcd')
set(['c', 'b'])
6
Aaron Hall

-」は、異なる単語を同じ単語に結合するために、いくつかの複合単語(たとえば、「オンサイト」)で使用されます。プログラミング言語でさまざまな文字列を結合するために「-」を使用しないのはなぜですか?それは完全に理にかなっていると思います!この+ナンセンスで地獄に!

ただし、これをもう少し抽象的な角度から見てみましょう。

文字列代数をどのように定義しますか?あなたはどのような事業を行い、どのような法律をそれらに適用しますか?彼らの関係はどうなりますか?

あいまいさはまったくないかもしれません。これを行うことが不可能であると言っても、可能なすべてのケースを明確に定義する必要があります!代数が小さいほど、これはより簡単になります。

たとえば、実際に2つの文字列を加算または減算するとはどういう意味ですか?

2つの文字列を追加する場合(たとえば、a = "aa"b = "bb"を許可)、a + bの結果としてaabbを取得しますか?

b + aはどうですか?それはbbaaでしょうか?なぜaabbではないのですか?加算結果からaaを減算するとどうなりますか?あなたの文字列には、マイナスの量のaaの概念がありますか?

この回答の最初に戻って、文字列の代わりにspaceshuttleを使用してください。一般化するために、どのタイプに対してどのような操作が定義されているか、または定義されていないのですか?

私が言いたいのは、何でも代数を作成することを妨げるものは何もないということです。意味のある操作、またはそれに役立つ操作を見つけるのは難しいかもしれません。

文字列の場合、連結は、私がこれまでに遭遇した唯一の賢明なものです。操作を表すのにどの記号を使用してもかまいません。

3
Zavior