7

Java のような言語には、char プリミティブと string クラスがあることに気付きました。Python や Ruby などの他の言語には、文字列クラスしかありません。これらの言語では、代わりに長さ 1 の文字列を使用して文字を表します。

その違いは歴史的な理由によるものなのだろうかと思っていました。Java に直接影響を与えた言語には char 型がありますが、文字列はありません。文字列は、代わりに char* または char[] を使用して形成されます。

しかし、そのようにすることに実際の目的があるかどうかはわかりませんでした。また、特定の状況で、ある方法が別の方法よりも優れているかどうかにも興味があります。

Ruby や Python などの言語では区別されないのに、Java などの言語では char プリミティブと文字列クラスが区別されるのはなぜですか?

確かに、慣例、効率、明快さ、実装の容易さなど、何らかの設計上の懸念があるに違いありません。言語設計者は、いわば帽子から文字表現を本当に選んだのでしょうか?

4

5 に答える 5

4

肝心なのは、言語設計者がそれを作成することを決定した方法です。それ以上遠くに行くのは難しいです。

ただし、C についての 1 つのポイントは、構文が実行されるデータとタスクの性質をより正確に反映するという点で、一般に低レベル言語と見なされます。文字を文字列として扱うことは、C の特徴ではない抽象化のレベルになります。それによって、内部のデータがどのようなものであるかがわかりにくくなります。また、必要なのが文字だけの場合、ほぼ確実にオーバーヘッドが追加されます。

C 型言語は単一の文字列をサポートしているため、私の意見では、両方の長所を実際に活用していることに注意してください。

于 2013-02-21T19:15:02.280 に答える
4

EDIT 1ソースへのリンクをいくつか追加しました。Lisp の歴史的なストーリーを改善しました。Javaにプリミティブがある理由に答えました。 EDIT 2効率がもはやそれほど問題ではないことを説明する最新のスクリプト言語に関するコメント

昔は、メモリは高価でした。単純なコンピュータでさえ数キロバイトしかありませんでした。同意しなければならない一般的なサービス条件は、システム全体の RAM を超えます。つまり、データ構造は、現在設計できるものよりもはるかに小さくする必要がありました

コンピュータは 1940 年代に英国と米国で始まりました。これらのエンジニアに必要な最小限の文字セットは、刺激的なアクセントのない西ヨーロッパのアルファベットでした。0 ~ 9、A ~ Z、および a ~ z は 62 文字です。31 個の制御文字、スペース、句読点を追加すると、すべてを 7 ビットに収めることができます。テレタイプに最適です。

現在、これらの 7 ビットは、異なるアーキテクチャで異なる方法で配置できます。IBM を使用していた場合、 ASCIIとはまったく異なるEBCDICを知っている必要がありました。

60 年代と 70 年代の言語はこれらの問題を反映しており、文字列を可能な限り小さなスペースに詰め込みました。

これらの言語のプログラマーとして、これはひどいものだと言えます。特に、ほとんどのビジネス プログラムでは多くのテキスト入力と操作が必要でした。メモリが安価になるにつれて、プログラマーは生産的なことを行うために何よりも先に文字列ユーティリティを作成する傾向がありました。

固定長の文字列 (Pascal など) は効率的でしたが、1 文字でも拡張または縮小する必要がある場合は厄介でした。

C の null で終了するアプローチには、長さが文字列と共に格納されないという欠点があるため、バッファを上書きしてアプリケーションをクラッシュさせるのは簡単です。このようなバグは、依然としてコンピューターのセキュリティを損なう主な原因となっています。これを解決するには、次の 2 つの方法があります。

  • 書き込みごとに文字列の長さを確認します。これは、ヌル文字が見つかるまでメモリをスキャンすることを意味します。醜い
  • malloc新しいメモリにコピーし、文字列を新しいメモリにコピーしてから、free

80 年代には、文字列を処理するために標準ライブラリがますます導入されました。これらは、ツール ベンダーと OS プロバイダーによって提供されました。標準化への大きな動きがありましたが、当事者は標準を管理するために歯と爪で戦い、醜いものでした。

国際化の進行は、国際文字セットという別の問題ももたらしました。最初に、ASCII はさまざまなヨーロッパ言語 (アクセント、ギリシャ語、キリル文字) のISO 8859-1として 8 ビットに拡張され、次にUnicodeによってコンピューターが世界の隅々まで完全に普及しました。そして、それはUTF-8UTF-16などの文字エンコーディングの問題と、これらの異なるアプローチの間でどのように変換するかという問題をもたらしました。

また、 Lispがガベージ コレクションを導入したことにも注意してください。mallocこれにより、C の/の複雑さが解決されfreeます。Lisp の信じられないほど強力な配列およびシーケンス ライブラリは、文字列に対して自然に機能します。

これらの傾向をまとめた最初の主要な人気のある言語は Java でした。言語の3 つの改善点を組み合わせました。

  1. 国際化と Unicode: 固有のデータ型Characterとプリミティブchar
  2. カプセル化: 固定長とヌル終端の問題は、次の方法で回避されました。
    1. 不変であること
    2. VM と GC での巧妙な最適化
  3. ライブラリ: すべての基本的な文字列操作機能は言語で標準化されました。

現在、すべての値がオブジェクトである言語があります。しかし、Java が 90 年代後半に考案されたとき、GC および JIT/Hotspot テクノロジは現在ほど高速ではありませんでした (少なくとも部分的には RAM の制限が原因でしたが、アルゴリズムも改善されました)。Gosling はパフォーマンスに気を配り、プリミティブなデータ型を維持しました。

もう 1 つのポイント: Java では Character クラスが存在するのは当然です。これは、 や などの多くの操作とユーティリティ メソッドの自然なホームですisWhiteSpace()isLetter()後者は、日本語、韓国語、およびインドの言語によって多少複雑になります。

Python は、文字を 8 ビット ASCII として定義するという不適切な初期の決定を下しました。微妙に異なり、互換性のない別のデータ型 (unicode) を最初に導入することで、結果として生じる問題を確認できます。これは、Python 3.x への複雑な移行によってのみ解決されます。

現代の言語 (スクリプト言語を含む) は、Java や Python に例示されるように、文字列ライブラリがどのように見えるべきかについて幅広いコンセンサスに従っています。

各言語は特定の目的のために設計されているため、さまざまな方法で競合する設計上の問題のバランスを取ります。現代の言語は、過去 60 年間にパフォーマンスとメモリが大幅に改善されたという利点があるため、CPU と RAM の効率よりも一般化、純粋性、および有用性を優先することができます。これは、スクリプトの性質上、既にその決定を行っているスクリプト言語に明確に当てはまります。したがって、現代の言語は、高レベルの文字列型のみを持つ傾向があります。

TL/DR初期のコンピューターはメモリが驚くほど限られていたため、最も単純な実装が必要でした。現代の言語は、GC が国際化 (8 ビットから 16 ビット) 文字を認識し、文字列データ型をカプセル化して、文字列操作を安全かつ簡単にすることの恩恵を受けています。

于 2013-03-05T08:28:44.013 に答える
2

さて、この問題に関する私の認識は、ここでの回答のいくつかを何らかの形で反映しているかもしれませんが、とにかくそれを言います:

はい、(他の皆さんが述べているように) C などの低レベル言語は、Perl、Ruby、または Python などのスクリプト言語よりも、最適化、パフォーマンス、およびマシン レベルの詳細をはるかに考慮に入れます。この "フル コントロール" の考え方の結果として、スクリプト言語と比較して、一般的に心配することが多くなります。

それで、私は何を言おうとしていますか?SO のメンバーが私に「Zen of Python」を渡したことがあるのですが、そのドキュメントからのほんの一部の抜粋に、「読みやすさの重要性」、「単純は複雑よりも優れている」などの主要な Python 哲学が含まれており、"There should be one-- and preferably only one --obvious way to do it.私はその最後の抜粋を強調しました。理由があります。

次に、char 型を持つ抽象プログラミング言語の例を示します: SML。たとえば、インタラクティブ モードで行う次の 2 つのステートメントを考えてみましょう。

- val a = "a"
val a = "a" : string    #interpreter type feedback

- val a = #"a"
val a = #"a" : char     #interpreter type feedback

上記の 2 つの例では、人間が読める 1 つの文字を表す 2 つの方法がありましたが、これらは基本的に異なる型です。SML は、今日の標準から見ると比較的抽象的な言語ですが、その中核となる哲学は、計算、数学的に表現可能な構文、およびバグの安全性にあります。最後の点は、純粋に機能的な言語 (SML は純粋ではありません) の場合はなおさらです。したがって、抽象化は低レベル言語の恐ろしい詳細から離れることを強調していますが、Python のような言語ほど「読みやすさ」や「使いやすさ」などの概念を重視していません。

実際、スクリプト言語は一般に、コードの迅速な生成と、習得と使用が容易な構文を強調しています。Rubyに関して言えば、松本自身も「使って楽しい」言語であるべきだと宣言していました。基本的に、私の最も謙虚な見積もりでは、Python のような言語で char データ型と string データ型を区別しない理由は、単純さの概念に含まれていると思います。冗長性と畳み込みは、スクリプト言語の敵のようです。さらに、最後のポイントとして、C 互換のデータ型を使用したい場合は、ctypesPython 用のライブラリーがあります。

于 2013-03-05T07:45:55.113 に答える
1

C および C++ では、acharは単なる「小さい」整数です。その名前が示すように文字エンコーディングに使用されますが、少なくともデスクトップ システム、またはさまざまな言語やアルファベットをサポートする必要があるシステムでの Unicode に直面して、その使用は減少しています。ただし、これらはハードウェアに直接アクセスできる「システムレベル」の言語であるため、特定のアーキテクチャでアドレス可能な最小のメモリユニットをアドレス指定できるデータ型も必要です。charそれが aが必要な理由です。

charC#では、文字エンコーディングに使用される型 (実際には 16 ビット) と、アドレス可能な最小単位の型byteである 8 ビットが区別されます。そのような明確さは、おそらくパーティーに後から参加することの利点です.

もちろん、Cには実際には文字列データ型はまったくありません.NULで終了する文字配列の規則と、その規則を使用する関数のライブラリがあるだけです(ちなみに、ここで説明されているように、単純ですが非効率的な規則です)。C++ では、文字列クラスは真の文字列型の利点をもたらし、いくつかの非効率性と危険性を回避できます (ただし、危険性を軽減すると、独自の異なるパフォーマンス ヒットが追加されます)。

于 2013-02-21T21:17:55.140 に答える
1

その区別が歴史的な理由によるものなのか (C には char しかなく、文字列は char* または char[] で形成される)、それともそのようにする実際の目的があるのか​​どうかはわかりませんでした。また、特定の状況で、ある方法が別の方法よりも優れているかどうかにも興味があります。

C文字列」の概念では、終了文字で終了する文字配列/一連の文字\0です。それ以外の場合、「文字列」は の他の配列と同様Cです。

たとえばC#、他のいくつかの言語では、文字列は抽象化として扱われ、文字列は不透明なオブジェクトに似ています。このオブジェクトには、文字列に対して機能するメソッドが含まれていますが、文字列が正確にどのように格納されるかは、プログラマには「隠されています」。

その理由は、C がはるかに古い言語であり、新しい言語よりもハードウェアに近いためです。

言語で文字列がどのように定義されるか (一重引用符または二重引用符が使用されるかどうか) は、言語を設計する人が当時良いことだと考えていた実装の詳細にすぎません。

于 2013-02-21T19:39:29.843 に答える