ข้อผิดพลาดในการคอมไพล์เวลานี้เกิดขึ้นเมื่อคุณพยายามกำหนดหรือส่ง (หรือแปลง) ชนิดที่เป็นรูปธรรมให้กับประเภทอินเตอร์เฟส และประเภทของตัวเองไม่ได้ใช้อินเตอร์เฟซเพียงตัวชี้ไปยังชนิด
ลองดูตัวอย่าง:
type Stringer interface {
String() string
}
type MyType struct {
value string
}
func (m *MyType) String() string { return m.value }
ประเภทอินเตอร์เฟซที่มีวิธีการหนึ่งเท่านั้น:Stringer
String()
ค่าใด ๆ ที่เก็บไว้ในค่าอินเทอร์เฟซStringer
ต้องมีวิธีนี้ นอกจากนี้เรายังสร้างMyType
และเราสร้างวิธีที่MyType.String()
มีตัวรับสัญญาณตัวชี้ ซึ่งหมายความว่าString()
วิธีการที่อยู่ในวิธีการตั้งค่าของ*MyType
ประเภท MyType
แต่ไม่ได้อยู่ในที่ของ
เมื่อเราพยายามกำหนดค่าMyType
ให้กับตัวแปรประเภทStringer
เราได้รับข้อผิดพลาดดังกล่าว:
m := MyType{value: "something"}
var s Stringer
s = m // cannot use m (type MyType) as type Stringer in assignment:
// MyType does not implement Stringer (String method has pointer receiver)
แต่ทุกอย่างก็โอเคถ้าเราพยายามกำหนดค่าประเภท*MyType
ให้กับStringer
:
s = &m
fmt.Println(s)
และเราได้ผลลัพธ์ตามที่คาดหวัง (ลองดูที่สนามเด็กเล่นโก ):
something
ดังนั้นข้อกำหนดในการรับข้อผิดพลาดในการรวบรวมนี้:
- ค่าของชนิดคอนกรีตที่ไม่ใช่ตัวชี้กำลังถูกกำหนด (หรือผ่านหรือแปลง)
- ประเภทอินเตอร์เฟสที่ถูกกำหนดให้ (หรือส่งผ่านไปยังหรือแปลงเป็น)
- ชนิดคอนกรีตมีวิธีการที่จำเป็นของอินเทอร์เฟซ แต่มีตัวรับสัญญาณตัวชี้
ความเป็นไปได้ในการแก้ไขปัญหา:
- ต้องใช้ตัวชี้ไปยังค่าซึ่งชุดวิธีการจะรวมวิธีการกับตัวรับสัญญาณตัวชี้
- หรือประเภทผู้รับต้องเปลี่ยนเป็นไม่ใช่ตัวชี้ดังนั้นวิธีการตั้งค่าประเภทคอนกรีตไม่ชี้จะประกอบด้วยวิธี (และตอบสนองอินเทอร์เฟซ) สิ่งนี้อาจเป็นไปได้หรืออาจจะใช้ไม่ได้ราวกับว่าวิธีการนั้นมีการแก้ไขค่าตัวรับสัญญาณที่ไม่ใช่ตัวชี้นั้นไม่ใช่ตัวเลือก
โครงสร้างและการฝัง
เมื่อใช้structs และฝังมักจะเป็นไม่ได้ "คุณ" ที่ใช้อินเตอร์เฟซ (ให้ดำเนินการตามวิธีการ) struct
แต่ชนิดที่คุณสามารถฝังในของคุณ เหมือนในตัวอย่างนี้:
type MyType2 struct {
MyType
}
m := MyType{value: "something"}
m2 := MyType2{MyType: m}
var s Stringer
s = m2 // Compile-time error again
อีกครั้งข้อผิดพลาดในการรวบรวมเพราะชุดวิธีการMyType2
ไม่ได้มีString()
วิธีการฝังตัวMyType
เพียงชุดวิธีการ*MyType2
ดังนั้นจึงทำงานต่อไปนี้ (ลองบนสนามเด็กเล่น Go ):
var s Stringer
s = &m2
เราสามารถทำให้มันใช้งานได้หากเราฝัง*MyType
และใช้ตัวชี้ที่ไม่ใช่ตัวชี้ MyType2
(ลองใช้บนสนามเด็กเล่น Go ):
type MyType2 struct {
*MyType
}
m := MyType{value: "something"}
m2 := MyType2{MyType: &m}
var s Stringer
s = m2
นอกจากนี้สิ่งที่เราฝัง (อย่างใดอย่างหนึ่งMyType
หรือ*MyType
) ถ้าเราใช้ตัวชี้*MyType2
มันจะทำงานได้เสมอ (ลองบนสนามเด็กเล่น Go ):
type MyType2 struct {
*MyType
}
m := MyType{value: "something"}
m2 := MyType2{MyType: &m}
var s Stringer
s = &m2
ส่วนที่เกี่ยวข้องจากข้อมูลจำเพาะ (จากหมวดโครงสร้างส่วน):
รับประเภท struct S
และชื่อประเภทT
วิธีการเลื่อนระดับจะรวมอยู่ในชุดวิธีการ struct ดังนี้
- หาก
S
มีข้อมูลที่ไม่ระบุชื่อT
วิธีการที่ชุดS
และทั้งสองรวมถึงวิธีการส่งเสริมการลงทุนกับเครื่องรับ*S
T
ชุดวิธีการนอกจากนี้ยังมีวิธีการที่มีการรับการเลื่อนตำแหน่ง*S
*T
- หาก
S
มีข้อมูลที่ไม่ระบุชื่อ*T
วิธีการที่ชุดS
และ*S
ทั้งสองรวมถึงวิธีการส่งเสริมการลงทุนกับเครื่องรับหรือT
*T
ดังนั้นในคำอื่น ๆ : หากเราฝังประเภทที่ไม่ใช่ตัวชี้ชุดวิธีการฝังตัวไม่ใช่ชี้ได้รับวิธีการที่มีตัวรับสัญญาณที่ไม่ใช่ตัวชี้ (จากประเภทฝัง)
หากเราฝังชนิดตัวชี้ชุดวิธีของตัวฝังแบบไม่ใช่ตัวชี้จะรับเมธอดที่มีทั้งตัวชี้และตัวรับสัญญาณที่ไม่ใช่ตัวชี้ (จากชนิดแบบฝัง)
หากเราใช้ค่าตัวชี้ไปยังตัวฝังโดยไม่คำนึงว่าชนิดที่ฝังตัวเป็นตัวชี้หรือไม่ชุดวิธีการของตัวชี้ไปยังตัวฝังจะได้รับวิธีการที่มีทั้งตัวชี้และตัวรับที่ไม่ใช่ตัวชี้ (จากชนิดที่ฝังตัว)
บันทึก:
มีกรณีที่คล้ายกันมากคือคือเมื่อคุณมีค่าอินเตอร์เฟซที่ตัดค่าMyType
และคุณพยายามที่จะพิมพ์ยืนยันStringer
ค่าอินเตอร์เฟซที่อื่นจากนั้น ในกรณีนี้การยืนยันจะไม่ถือด้วยเหตุผลที่อธิบายไว้ข้างต้น แต่เราได้รับข้อผิดพลาด runtime แตกต่างกันเล็กน้อย:
m := MyType{value: "something"}
var i interface{} = m
fmt.Println(i.(Stringer))
รันไทม์ตกใจ (ลองไปที่สนามเด็กเล่นไป ):
panic: interface conversion: main.MyType is not main.Stringer:
missing method String
ความพยายามในการแปลงแทนการยืนยันประเภทเราได้รับข้อผิดพลาดเวลาคอมไพล์ที่เรากำลังพูดถึง:
m := MyType{value: "something"}
fmt.Println(Stringer(m))
func (m *MyType)
" หรือไม่มี มันเป็นอย่างนั้นเหรอ? ฉันสามารถผสม "ฟังก์ชั่นสมาชิก" ที่แตกต่างกันเช่นfunc (m *MyType)
&func (m MyType)
?