không thể chuyển đổi dữ liệu (kiểu giao diện {}) thành kiểu chuỗi: cần xác nhận kiểu


176

Tôi khá mới để đi và tôi đã chơi với gói thông báo này .

Lúc đầu tôi có mã trông như thế này:

func doit(w http.ResponseWriter, r *http.Request) {
    notify.Post("my_event", "Hello World!")
    fmt.Fprint(w, "+OK")
}

Tôi muốn nối thêm dòng mới vào Hello World!nhưng không phải trong chức năng doittrên, vì điều đó sẽ khá tầm thường, nhưng handlersau đó như sau:

func handler(w http.ResponseWriter, r *http.Request) {
    myEventChan := make(chan interface{})
    notify.Start("my_event", myEventChan)
    data := <-myEventChan
    fmt.Fprint(w, data + "\n")
}

Sau go run:

$ go run lp.go 
# command-line-arguments
./lp.go:15: invalid operation: data + "\n" (mismatched types interface {} and string)

Sau một chút Googling tôi đã tìm thấy câu hỏi này trên SO .

Sau đó, tôi cập nhật mã của mình thành:

func handler(w http.ResponseWriter, r *http.Request) {
    myEventChan := make(chan interface{})
    notify.Start("my_event", myEventChan)
    data := <-myEventChan
    s:= data.(string) + "\n"
    fmt.Fprint(w, s)
}

Đây có phải là những gì tôi phải làm? Lỗi trình biên dịch của tôi không còn nữa nên tôi đoán nó khá tốt? Đây có phải là hiệu quả? Bạn nên làm điều đó khác nhau?

Câu trả lời:


291

Theo thông số kỹ thuật của Go :

Đối với một biểu thức x của loại giao diện và loại T, biểu thức chính x. (T) khẳng định rằng x không phải là số không và giá trị được lưu trữ trong x là loại T.

"Xác nhận kiểu" cho phép bạn khai báo một giá trị giao diện chứa một loại cụ thể nhất định hoặc loại cụ thể của nó đáp ứng giao diện khác.

Trong ví dụ của bạn, bạn đã xác nhận dữ liệu (kiểu giao diện {}) có chuỗi kiểu cụ thể. Nếu bạn sai, chương trình sẽ hoảng loạn khi chạy. Bạn không cần phải lo lắng về hiệu quả, kiểm tra chỉ yêu cầu so sánh hai giá trị con trỏ.

Nếu bạn không chắc đó có phải là một chuỗi hay không, bạn có thể kiểm tra bằng cách sử dụng cú pháp trả về hai.

str, ok := data.(string)

Nếu dữ liệu không phải là một chuỗi, ok sẽ là sai. Sau đó, thông thường để bọc một câu lệnh như vậy thành một câu lệnh if như vậy:

if str, ok := data.(string); ok {
    /* act on str */
} else {
    /* not string */
}

29

Loại xác nhận

Điều này được gọi là type assertiontrong golang, và nó là một thực tế phổ biến.

Dưới đây là lời giải thích từ một tour du lịch của đi :

Một xác nhận kiểu cung cấp quyền truy cập vào giá trị cụ thể cơ bản của giá trị giao diện.

t := i.(T)

Tuyên bố này khẳng định rằng giá trị giao diện i giữ loại T cụ thể và gán giá trị T cơ bản cho biến t.

Nếu tôi không giữ chữ T, câu lệnh sẽ gây hoảng loạn.

Để kiểm tra xem một giá trị giao diện có giữ một loại cụ thể hay không, một xác nhận loại có thể trả về hai giá trị: giá trị cơ bản và giá trị boolean báo cáo xem xác nhận đó có thành công hay không.

t, ok := i.(T)

Nếu tôi giữ một T, thì t sẽ là giá trị cơ bản và ok sẽ là đúng.

Nếu không, ok sẽ là false và t sẽ là giá trị 0 của loại T và không có sự hoảng loạn nào xảy ra.

LƯU Ý: giá trị iphải là loại giao diện .

Cạm bẫy

Ngay cả khi ilà một loại giao diện, []ikhông phải là loại giao diện. Kết quả là, để chuyển đổi []ithành loại giá trị của nó, chúng ta phải thực hiện riêng lẻ:

// var items []i
for _, item := range items {
    value, ok := item.(T)
    dosomethingWith(value)
}

Hiệu suất

Đối với hiệu suất, nó có thể chậm hơn so với truy cập trực tiếp vào giá trị thực như được hiển thị trong câu trả lời stackoverflow này .


13
//an easy way:
str := fmt.Sprint(data)

21
Thêm một số lời giải thích với câu trả lời về cách câu trả lời này giúp OP khắc phục vấn đề hiện tại
ρяσѕρєя K

2

Khi được yêu cầu bởi @ ρяσѕρєя một lời giải thích có thể được tìm thấy tại https://golang.org/pkg/fmt/#Sprint . Giải thích liên quan có thể được tìm thấy tại https://stackoverflow.com/a/44027953/12817546 và tại https://stackoverflow.com/a/42302709/12817546 . Đây là câu trả lời của @ Yuanbo đầy đủ.

package main

import "fmt"

func main() {
    var data interface{} = 2
    str := fmt.Sprint(data)
    fmt.Println(str)
}

1
Tôi đoán bạn có thể kết hợp cả hai câu trả lời bằng cách chỉnh sửa @ Yuanbo - cả hai bạn sẽ được ghi có và cộng điểm 'hữu ích' tương ứng của bạn 😉
Gwyneth Llewelyn
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.