Golang の文字列型を変更できないのはなぜですか?

藏色散人
リリース: 2022-11-21 20:36:28
転載
1558 人が閲覧しました

この記事は、golang チュートリアル コラムで、golang における文字列型の変更の問題を紹介するために紹介されています。疑問に思われるかもしれません。日常の開発で文字列を変更するのは普通のことです。これは聞こえますか? Go の変更できない文字列についてはどうですか?以下に例を挙げて詳しく説明しますので、困っている友達のお役に立てれば幸いです。

Go のような言語に触れるとき、この文をよく聞くかもしれません。文字列は変更できないという事実について疑問に思われるかもしれませんが、日常の開発では文字列を変更するのは普通のことですが、なぜ Go の文字列は変更できないと言われるのでしょうか?

この記事では、Go で文字列を変更できない理由を実際のケースを通して説明します。

この問題を説明する前に、誰もが問題をさらに理解できるように、まず文字列型の基本的な知識について大まかに説明しましょう。

文字列の定義

文字列は、文字を表すために使用されるデータ型です。ご利用の際は文字内容を「 」で囲んでご利用ください。たとえば、次の形式です。

package main
import "fmt"
func main() {
    var str string = "Hello World!"
}
ログイン後にコピー

Go では、通常、文字列は 3 つの方法で定義されます。

// 第一种(全量定义)
var 变量名称 string = "字符串内容"
// 类型推导
var 变量名称 = "字符串内容"
// 短标记(只适用于局部变量)
变量名称 := "字符串内容"
ログイン後にコピー

文字列の定義はバイト単位で定義することもできます。ここにリストされている方法は最も一般的なものです。

文字列の構成

Go の文字列は Unicode 標準に準拠しており、UTF-8 でエンコードされます。文字列の最下層は実際にはバイトで構成されています (詳しくは後述します)。特定のバイトの内容を印刷および表示するには、次の例を使用します。

s := "Hello World!"
for _, v := range s {
    fmt.Print(v)
    fmt.Print("\t")
}
// 72 101 108 108 111 32 87 111 114 108 100 33
ログイン後にコピー

上記のコードによって印刷される内容は、各文字で表されるバイトコードです。

文字列は変更できません

上記の大まかなデモを通じて、文字列の基本を理解しました。文字列は変更できないのですが、日々の開発では文字列を再割り当てするのは普通のことですが、なぜ Go の文字列は変更できないと言えるのでしょうか?

実際、ここでこのステートメントを修正する必要があります。文字列の変更は再割り当てと同じではありません。開発で一般的に使用される方法は、実際には再割り当ての概念です。

str := "Hello World!"
// 重新赋值
str = "Hello Go!"
// 字符串修改
str[0] = "I"
ログイン後にコピー

通常、変更できないという話を聞きますが、これは実際には上記のコードの 2 番目の方法を指します。そして、この方法で変更すると、次のエラーが報告されます: :cannot assign to s [0] (value of type byte)

トピックに戻りますが、なぜ Go の文字列は添え字によって変更できないのでしょうか。

これは、Go の文字列データ構造がポインタと長さから構成される構造であり、ポインタが指すスライスが実際の文字列値であるためです。 Go のソース コードには次のような定義があります:

type stringStruct struct {
    str unsafe.Pointer // 指向一个byte类型的切片指针
    len int // 字符串的长度
}
ログイン後にコピー

Golang の文字列型を変更できないのはなぜですか?

これはまさに、最下層が [] バイト型のスライスであるためです。 , 今回はバイト型に文字コンテンツを割り当てることは絶対に許可されません。ただし、添え字を付けることで対応するバイト値にアクセスできます。

fmt.Println(s[0]) // output:72
ログイン後にコピー

それでは、添え字を付けて値を変更したい場合はどうすればよいでしょうか?このとき、スライスで定義してから文字列に変換する必要があります。

package main
import (  
    "fmt"
)
func main() {  
     s1 := []byte{72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33}
    fmt.Println(string(s1))
    // 将"H"修改为l
    s1[0] = 108
    fmt.Println(string(s1))
}
// output:
Hello World!
lello World!
ログイン後にコピー

文字列の代入

上記は添字を使用して文字列を代入できない理由を分析したものですが、日常の開発における代入方法に戻って答えてみましょう。

package main
import (  
    "fmt"
)
func main() {
    // 声明一个字符串,并给与初始值
    s := "Hello World!"
    // 对变量 s 进行重新赋值
    s := "Hello Go!"
}
ログイン後にコピー

では、なぜこのシナリオで文字列を再割り当てできるのでしょうか?

これは、Go の下部で [] byte {} 型のスライスが実際に新しく作成され、変数 s のポインタが新しいメモリ空間アドレス (つまり、Hello Go!) を指しているためです。ここ! )。元の Hello World! メモリ空間は、ガベージ コレクション メカニズムによって再利用されます。

Golang の文字列型を変更できないのはなぜですか?

なぜこのように設計されているのか

おそらく、通常の文字列の設計が非常に複雑で、ポインターを使用する必要がある理由を誰もが考えるでしょう。

私の個人的な推測では、非常に長い文字に遭遇した場合、これにより文字列が非常に軽量になり、メモリのコピーを気にせずに簡単に転送できるようになります。 Goでは参照型でも値型のパラメータ渡しでも値渡しになりますが。ただし、ポインターは値渡しよりも明らかにメモリ効率が高くなります。

以上がGolang の文字列型を変更できないのはなぜですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:learnku.com
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート