Lỗi thời gian biên dịch này phát sinh khi bạn cố gắng gán hoặc chuyển (hoặc chuyển đổi) một loại cụ thể thành một loại giao diện; và kiểu chính nó không thực hiện giao diện, chỉ có một con trỏ tới kiểu .
Hãy xem một ví dụ:
type Stringer interface {
String() string
}
type MyType struct {
value string
}
func (m *MyType) String() string { return m.value }
Các Stringer
loại giao diện có một phương pháp duy nhất: String()
. Bất kỳ giá trị nào được lưu trữ trong một giá trị giao diện Stringer
đều phải có phương thức này. Chúng tôi cũng đã tạo một MyType
và chúng tôi đã tạo một phương thức MyType.String()
với bộ thu con trỏ . Điều này có nghĩa là String()
phương thức nằm trong tập phương thức của *MyType
kiểu, nhưng không phải trong phương thức đó MyType
.
Khi chúng ta cố gắng gán giá trị MyType
cho một biến loại Stringer
, chúng ta sẽ gặp lỗi trong câu hỏi:
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)
Nhưng mọi thứ đều ổn nếu chúng ta cố gắng gán giá trị của loại *MyType
cho Stringer
:
s = &m
fmt.Println(s)
Và chúng tôi nhận được kết quả mong đợi (thử trên Sân chơi Go ):
something
Vì vậy, các yêu cầu để có được lỗi thời gian biên dịch này:
- Một giá trị của loại bê tông không con trỏ được gán (hoặc được chuyển hoặc chuyển đổi)
- Một loại giao diện được gán cho (hoặc được chuyển đến hoặc chuyển đổi thành)
- Loại bê tông có phương thức cần thiết của giao diện, nhưng với một bộ nhận con trỏ
Khả năng giải quyết vấn đề:
- Phải sử dụng một con trỏ tới giá trị, có tập phương thức sẽ bao gồm phương thức với bộ nhận con trỏ
- Hoặc loại máy thu phải được thay đổi thành không phải con trỏ , do đó, tập phương thức của loại bê tông không con trỏ cũng sẽ chứa phương thức (và do đó thỏa mãn giao diện). Điều này có thể hoặc không thể tồn tại, vì nếu phương thức phải sửa đổi giá trị, một bộ thu không phải là con trỏ không phải là một tùy chọn.
Cấu tạo và nhúng
Khi sử dụng cấu trúc và nhúng , thường không phải là "bạn" thực hiện giao diện (cung cấp cách thực hiện phương thức), mà là loại bạn nhúng vào struct
. Giống như trong ví dụ này:
type MyType2 struct {
MyType
}
m := MyType{value: "something"}
m2 := MyType2{MyType: m}
var s Stringer
s = m2 // Compile-time error again
Một lần nữa, lỗi thời gian biên dịch, vì tập phương thức MyType2
không chứa String()
phương thức được nhúng MyType
, chỉ có tập phương thức *MyType2
, do đó, các công việc sau (thử trên Sân chơi Go ):
var s Stringer
s = &m2
Chúng tôi cũng có thể làm cho nó hoạt động, nếu chúng tôi nhúng *MyType
và chỉ sử dụng một con trỏ không MyType2
(thử nó trên Sân chơi Go ):
type MyType2 struct {
*MyType
}
m := MyType{value: "something"}
m2 := MyType2{MyType: &m}
var s Stringer
s = m2
Ngoài ra, bất cứ điều gì chúng tôi nhúng (hoặc MyType
hoặc *MyType
), nếu chúng tôi sử dụng một con trỏ *MyType2
, nó sẽ luôn hoạt động (thử trên Sân chơi Go ):
type MyType2 struct {
*MyType
}
m := MyType{value: "something"}
m2 := MyType2{MyType: &m}
var s Stringer
s = &m2
Phần có liên quan từ thông số kỹ thuật (từ phần Kiểu cấu trúc ):
Cho một kiểu cấu trúc S
và một kiểu có tên T
, các phương thức được thăng cấp được bao gồm trong tập phương thức của cấu trúc như sau:
- Nếu
S
chứa một trường ẩn danh T
, tập hợp phương thức S
và *S
cả hai bao gồm các phương thức được quảng cáo với người nhận T
. Bộ phương thức *S
cũng bao gồm các phương thức được quảng bá với máy thu *T
.
- Nếu
S
chứa một trường ẩn danh *T
, bộ phương thức S
và *S
cả hai bao gồm các phương thức được quảng cáo với người nhận T
hoặc *T
.
Vì vậy, nói cách khác: nếu chúng ta nhúng một loại không phải con trỏ, tập phương thức của bộ nhúng không con trỏ chỉ nhận được các phương thức với các bộ thu không con trỏ (từ loại được nhúng).
Nếu chúng ta nhúng một loại con trỏ, tập hợp phương thức của bộ nhúng không con trỏ sẽ nhận các phương thức với cả hai bộ thu con trỏ và không con trỏ (từ loại được nhúng).
Nếu chúng ta sử dụng một giá trị con trỏ cho trình nhúng, bất kể kiểu nhúng có phải là con trỏ hay không, tập phương thức của con trỏ tới trình nhúng luôn lấy các phương thức có cả con trỏ và con trỏ không con trỏ (từ kiểu nhúng).
Ghi chú:
Có một trường hợp rất giống nhau, cụ thể là khi bạn có một giá trị giao diện bao bọc một giá trị MyType
và bạn cố gắng nhập xác nhận giá trị giao diện khác từ nó , Stringer
. Trong trường hợp này, xác nhận sẽ không giữ vì các lý do được mô tả ở trên, nhưng chúng tôi nhận được một lỗi thời gian chạy hơi khác:
m := MyType{value: "something"}
var i interface{} = m
fmt.Println(i.(Stringer))
Thời gian chạy hoảng loạn (thử nó trên Sân chơi Go ):
panic: interface conversion: main.MyType is not main.Stringer:
missing method String
Cố gắng chuyển đổi thay vì xác nhận kiểu, chúng tôi nhận được lỗi thời gian biên dịch mà chúng tôi đang nói đến:
m := MyType{value: "something"}
fmt.Println(Stringer(m))
func (m *MyType)
" hoặc không có . Có phải vậy không Tôi có thể trộn các loại "hàm thành viên" khác nhau không, ví dụ:func (m *MyType)
&func (m MyType)
?