Go 语言 指针 语言 指针 语言 Go 语言
指针类型ที่เอาไว้เก็บ地址แต่ถ้าจะให้เข้าใจต้องถามต่อไปว่า地址กันไปทำไม
多变的
记忆记忆机器码การอ้างอิงหน่วยเก็บข้อมูลใน内存จะใช้หมายเลข地址แต่อย่างไรก็ตามภาษาคอมพิวเตอร์ที่ สร้างขึ้นมาเพื่อให้เราไม่ต้องเขียน机器码去吧地址 กันแล้ว变量 变量เนี่ยให้เราใช้ซึ่งเราก็ใช้ชื่อตัวแปร แทนที่ตำแหน่งเก็บข้อมูลเช่น
package main
import (
"fmt"
)
func main() {
a := 10
b := 20
c := a + b
fmt.Println(c)
}
เราก็มีที่เก็บข้อมูลชื่อ a เก็บ 10 ชื่อ b เก็บ 20 และ c เก็บผลลัพธ์ที่ได้ของ a + b คือ 30
指针指针เลยถูกมั้ยครับ变量作用域,กฎเกณฑ์ในการส่งค่าไปให้ฟังก์ชันและการ返回Go 语言 Go 语言 Go 语言 Go 语言 Go 语言ออกแบบเอาไว้ทำอะไร
范围
ตัวแปรใช้ชื่อในการอ้างอิง แต่ว่าก็มีขอบเขตในการอ้างอิงชื่อนั้นเช่นกัน范围 范围 范围 Go 范围指针作用域 作用域
函数功能和尚ฟังก์ชันอื่นๆอาจจะมีชืน่อตัวแปรเหมือกันได้ แต่ก็ถือว่าเป็นคนละตัวกันเช่น
package main
import (
"fmt"
)
func sayHello(name string) {
msg := "Hello " + name
fmt.Println(msg)
}
func main() {
var msg string
sayHello("Por")
fmt.Println("Main => ", msg)
}
เมื่อรันโปรแกรมนี้จะได้
Hello Por
Main =>
จะเห็นว่าตัวแปร msg ใน main function ไม่ใช่ตัวเดียวกันกับ msg ใน sayHello แม้จะชื่อเหมือนกันก็ตาม
函数功能
函数 参数 参数 参数เวลาเราเรียกใช้งานเราก็ต้องส่งค่าไปด้วย去吧复制品参数设置
package main
import (
"fmt"
)
func add(a, b int) int {
return a + b
}
func main() {
fmt.Println(add(10, 20))
}
เมื่อเราเรียกadd(10, 20)ตัวแปร a และ b ที่เป็น参数ของ功能添加复制 ค่า 10 และ 20 ให้ตามลำดับ
ถ้าเรียกแบบนี้
func main() {
a := 10
b := 20
fmt.Println(add(a, b))
}
ั่นคือมีตัวแปร a และ b ใน main อยู่แล้วแต่ตอเรียกadd(a, b)复制 ค่า a และ b ของ main ไปให้ a และ b ที่เป็น 参数 ของ 添加功能范围แม้ชื่อเหมือนกันแต่เป็นคนละตัว
返回值函数
返回值函数复制品功能添加功能添加功能
package main
import (
"fmt"
)
func add(a, b int) int {
c := a + b
return c
}
func main() {
a := 10
b := 20
c := add(a, b)
fmt.Println(c)
}
添加并添加 添加添加return c复制 ค่าของ c ออกไปเมื่อเรากำหนดผลลัพธ์ของadd(a, b)ให้ c ใน main function ใ็จะเกิดตัวแปร c อีกตัวที่มีscope ใน main function โดย copy ค่าที่ 返回 ได้กลับมาเก็บไว้ในตัวแปร c
去吧ในการส่งค่าและรีเทิร์น ค่ากลับมาเป็นแบบนี้เสมอ复制范围ของอีกฟังก์ชันให้กับอีกฟังก์ชัน参数 参数 返回 参数 返回值类型อะไรก็ตาม
复制品
จริงๆแล้วทุกๆการกำหนดค่าของ去复制ค่าจากที่หนึ่งไปอีกที่หนึ่งทั้งหมดเช่น
a := 10
b := a
c := b
ก็คือ a, b และ c เป็นคนละตัวแปร และการกำหนดค่า复制品:==ค่าจากด้านขวาไปทางด้านซ้ายทั้งหมด
复制功能 复制ด้วยเพราะมันก็คือการกำหนดค่าเห มือนกันคือกำหนดค่าให้กับตัวแปร 范围ของฟังก์ชันนั่นเอง
指针
指针指针พอเรารู้ว่าทุกอย่างในการส ่งค่าไปให้ฟังก์ชันเป็นการ复制 เสมอ功能 功能 功能เช่น
package main
import (
"fmt"
"strings"
)
func upperAllLetter(str string) {
str = strings.ToUpper(str)
}
func main() {
name := "Weerasak"
upperAllLetter(name)
fmt.Println(name)
}
ซึ่งเราคาดว่าเรียกupperAllLetter(name)ค่าใน名称ต้องเปลี่ยนเป็น上部ทั้งหมดแต่ปรากฎว่าได้ ค่าเดิมเพราะเพื่อเรียก function มันคือการ复制名称主要参数str、函数str名称 ใน main
ถ้าเราอยากให้ฟังก์ชันที่เราเรีย กเปลี่ยนค่าของตัวแปรที่อยู่คนละ范围 ได้จริงๆต้องทำอย่างไร
ในGo指针โดยสิ่งที่指针เก็บคือ地址ของตัวแปรอื่นหรือตำแหน่งหน่วยความจำอื่นๆ ซึ่งก็ไม่ต่างกับตัวแปรอื่นๆ คือเกิดขึ้นมาเพื่อเก็บข้อมูล地址การได้มาซึ่งเลข 地址ใน Go ก็ไม่ใช่การกำหนดเลขมั่วๆ สิ่งที่เตรียมให้คือ操作员&ในการเอาค่า地址ออกมา (หรือใช้内置函数新地址ออกมาโดยไม่ต้องใช้ตัวแปร ซึ่งก็ไม่ค่อยได้ใช้เท่าไหร่ นานๆใช้ที)
เราไม่ได้ทำอะไรกับเลข地址???????????????????????????????????????????????????????????????????????????????????????????????????????????指针地址 操作员*
ตัวอย่างเช่น
package main
import (
"fmt"
)
func main() {
name := "Por"
// ถ้าประกาศโดยใช้ data type ด้วยก็คือใช้
// var pointerToName *string = &name
pointerToName := &name
*pointerToName = "Weerasak"
fmt.Println(name)
}
指针范围 เดียวกันหรอก จะทำทำไมเล่าก็เมื่อเราก็ใช้名称 范围 范围
指针มาใช้บ่อยที่สุดคือ เอามาใช้เวลาเราต้องการให้ฟังก์ชัน แก้ไขค่าของตัวแปรอื่นที่ส่งเข้ามา เพราะในเมื่อแก้ตรงๆไม่ได้ แต่เราส่ง指针มาเราจะใช้运算符*แก้อ้อมๆ(间接)ได้นั่นเอง
ที่นี้มาเขียนฟังก์ชัน upperAllLetter参数类型指针类型指针字符串类型指针字符串类型
package main
import (
"fmt"
"strings"
)
func upperAllLetter(str *string) {
*str = strings.ToUpper(*str)
}
func main() {
name := "Weerasak"
upperAllLetter(&name)
fmt.Println(name)
}
类型 参数 参数 名称เฉยๆไม่ได้แล้วเพราะมันจะผิด类型ของ参数指针指针 细绳
สิ่งที่เราทำได้ก็คือใช้操作员&เพื่อส่ง地址ของ名称ไปให้แทน
ผลการทำงานก็จะเห็นว่า name ของ main โดนเปลี่ยนไปด้วยตามที่ต้องการแล้ว โดยที่กฎเกณฑ์เรื่องการส่งค่ายังคงเดิมคือ COPY ค่าเหมือนเดิมแค่ในเคสนี้ค่าที่ถูก复制指针ที่เป็นเลข地址นั่นเอง
指针结构
Struct 类型 int、bool、string 类型 类型 类型类型 类型 类型 类型 类型 类型 类型 类型 类型 字段 结构体
字段 字段หรือเปลี่ยนค่าบาง字段ได้ผ่านทาง.(点)เช่น
package main
import (
"fmt"
)
type Profile struct {
Name string
Age int
}
func main() {
p := Profile{
Name: "Por",
Age: 35,
}
fmt.Println(p.Name)
fmt.Println(p.Age)
p.Name = "Weerasak"
fmt.Println(p.Name)
}
功能 功能 เพื่อแก้ไขค่าของ struct 结构体 函数 结构体
package main
import (
"fmt"
"strings"
)
type Profile struct {
Name string
Age int
}
func upperProfileName(p Profile) {
p.Name = strings.ToUpper(p.Name)
}
func main() {
p := Profile{
Name: "Por",
Age: 35,
}
upperProfileName(p)
fmt.Println(p.Name)
}
เวลาเราส่ง p ไป ก็คือการ 复制 p ให้กับ p复制 复制 字段 字段名称 名称 功能名称 名称 功能 主要功能
指针ช่วยได้เหมือนเดิมโดยเปลี่ยนโค้ดเป็แบบนี้
package main
import (
"fmt"
"strings"
)
type Profile struct {
Name string
Age int
}
func upperProfileName(p *Profile) {
p.Name = strings.ToUpper(p.Name)
}
func main() {
p := Profile{
Name: "Por",
Age: 35,
}
upperProfileName(&p)
fmt.Println(p.Name)
}
指针 struct struct struct struct คือเราสามารถใช้.点 ได้เลย ไม่ต้องใช้ 运算符*ในการแก้ไขค่าของ 字段 ผ่านทาง 指针เราจะใช้*struct struct 结构体ซึ่งก็ไม่บ่อยที่จะทำแบบนั้น
切片地图
切片 และ 地图 ของ Go จะพิเศษจากตัวแปรธรรมดาหน่อยเพรา ะมันถูกออกแบบมาให้เก็บข้อมูลแบบ动态大小 附加元素 切片หรือเอาออกก็ได้สำหรับ地图ก็เพิ่ม键值หรือลบออกก็ได้เช่นกัน
การจัดการภายในของ切片และ地图คือจะมีการเก็บ地址แบบ指针ั่นแหละของ元素เอาไว้ตัว切片นและ地图ไม่ใช่ก้อ元素เองโดยตรง
参数、切片、地图、复制เหมือนเดิมกับเหมือนตัวแปรอื่น类型 ใน Go复制 复制
切片、映射、复制、指针、复制地址复制元素 复制元素元素元素参数 切片 映射 映射 切片 映射ของฝั่งที่เรียกใช้ด้วยนั่นเองเช่น
package main
import (
"fmt"
)
func doubleAllElement(nums []int) {
for i := range nums {
nums[i] *= 2
}
}
func main() {
nums := []int{1, 2, 3}
doubleAllElement(nums)
fmt.Println(nums)
}
复制doubleAllElements(nums)nums 和 main 复制 nums 和 doubleAllElements แต่ว่าสิ่งที่复制ไปคือ地址ของ元素ด้วย元素 元素 doubleAllElements ก็จะกระทบกับelementของnumsในmainด้วย
乌鲁木齐地图 乌鲁木齐地图
package main
import (
"fmt"
)
func doubleAllElement(nums map[string]int) {
for key := range nums {
nums[key] *= 2
}
}
func main() {
nums := map[string]int{
"one": 1,
"two": 2,
"three": 3,
}
doubleAllElement(nums)
fmt.Println(nums)
}
复制 复制 复制地址 元素 元素 元素 元素 元素 元素
แต่ถ้าเราอยากให้เกิดการเปลี่ ยนแปลงกับตัวแปรทั้งก้อนจริงๆ指针类型 指针类型 指针类型解组功能JSON格式去吧指针เสมอแม้ว่าตัวแปรจะเป็น切片หรือ地图ก็ตามเพื่อจะได้เปลี่ยนแปลงข้ อมูลทั้งก้อนของตัวแปรได้ผ่าน指针 เช่นถ้าทำแบบนี้
package main
import (
"encoding/json"
"fmt"
)
func main() {
jsonText := []byte(`[1, 2, 3]`)
var nums []int
json.Unmarshal(jsonText, nums)
// ที่ถูกต้องเป็นแบบนี้ json.Unmarshal(jsonText, &nums)
fmt.Println(nums)
}
ตัวแปร nums จะไม่ได้ค่า[1, 2, 3]แน่นอน ที่ถูกต้องคือต้องเรียกjson.Unmarshal(jsonText, &nums)ส่ง地址(指针ของ切片[]int) ไปให้แทน
返回指针
函数功能เพื่อฟังก์ชันทำงานจบ重复使用 重复使用 重复使用返回复制เช่นกันตัวแปรเกิดใหม่ที่อ ีกฟังก์ชันที่เอามาเก็บค่า ก็ถือเป็นคนละตัวกัน
แต่บางครั้งเราต้องการสร ้างฟังก์ชันที่ทำหน้าที่安装程序设置设置ซับซ้อนแล้วต้องใช้หลายๆที่ เราก็ต้องการแยกเป็功能返回复制 复制 复制
指针 指针 指针返回数据 返回地址 返回地址指针指针函数功能类型 struct struct
package main
import (
"fmt"
)
type App struct {
db DB
conf Config
}
func NewApp() (*App, error) {
db, err := NewDB()
if err != nil {
return nil, err
}
conf, err := NewConf()
if err != nil {
return nil, err
}
<span class="k">return</span> <span class="o">&</span><span class="n">App</span> <span class="p">{</span>
<span class="n">db</span><span class="o">:</span> <span class="n">db</span><span class="p">,</span>
<span class="n">conf</span><span class="o">:</span> <span class="n">conf</span><span class="p">,</span>
<span class="p">},</span> <span class="no">nil</span>
}
func main() {
app, err := NewApp()
if err != nil {
panic(err)
}
app.Run()
}
สรุป
去吧 去吧 การกำหนดค่าให้ตัวแปร功能 ทุกอย่างคือการ 复制ค่าเสมอ
函数功能指针类型 运算符*指针เก็บเอาไว้อยู่นั่นเอง
