2012-07-09 13 views
60

Cách thành ngữ để truyền nhiều giá trị trả về trong Go là gì?Cách thành ngữ để thực hiện xác nhận chuyển đổi/loại trên nhiều giá trị trả lại trong Go

Bạn có thể làm điều đó trong một dòng, hay bạn cần sử dụng các biến tạm thời như tôi đã làm trong ví dụ dưới đây?

package main 

import "fmt" 

func oneRet() interface{} { 
    return "Hello" 
} 

func twoRet() (interface{}, error) { 
    return "Hejsan", nil 
} 

func main() { 
    // With one return value, you can simply do this 
    str1 := oneRet().(string) 
    fmt.Println("String 1: " + str1) 

    // It is not as easy with two return values 
    //str2, err := twoRet().(string) // Not possible 
    // Do I really have to use a temp variable instead? 
    temp, err := twoRet() 
    str2 := temp.(string) 
    fmt.Println("String 2: " + str2) 


    if err != nil { 
     panic("unreachable") 
    } 
} 

Nhân tiện, nó có được gọi là casting khi nói đến giao diện không?

i := interface.(int) 

Trả lời

55

Bạn không thể làm điều đó trong một dòng. Cách tiếp cận biến tạm thời của bạn là cách để đi.

Nhân tiện, nó được gọi là truyền khi nói đến giao diện?

Nó thực sự được gọi là type assertion. Một loại cast chuyển đổi khác nhau:

var a int 
var b int64 

a = 5 
b = int64(a) 
+10

Thực ra, điều đó cũng không được gọi là diễn viên. Nó được gọi là chuyển đổi. http://golang.org/ref/spec#Conversions –

+1

Cảm ơn bạn đã trả lời cả hai câu hỏi. Tôi đã chỉnh sửa tiêu đề để phù hợp hơn với câu hỏi. – ANisus

11

template.Must là cách tiếp cận các thư viện chuẩn của trả lại chỉ có giá trị trả về đầu tiên trong một tuyên bố. Có thể được thực hiện tương tự cho trường hợp của bạn:

func must(v interface{}, err error) interface{} { 
    if err != nil { 
     panic(err) 
    } 
    return v 
} 

// Usage: 
str2 := must(twoRet()).(string) 

Bằng cách sử dụng must về cơ bản bạn nói rằng có bao giờ phải là một lỗi, và nếu có, sau đó chương trình có thể không (hoặc ít nhất là không nên) tiếp tục điều hành và sẽ hoảng sợ thay thế.

+4

Không đơn giản để hoảng sợ về các lỗi không phải do lập trình viên gây ra. Một hàm như 'template.Must()' thường được sử dụng để tải các mẫu từ một biến trong các khai báo mức gói và các hàm 'init()'. Ý tưởng là để hoảng sợ ngay lập tức tại thời gian chạy và làm cho nó rõ ràng rằng một cái gì đó trình biên dịch không thể bắt là sai. Bạn không nên sử dụng điều này để tránh các biến tạm thời. –

+1

Và phần nào của "Bằng cách sử dụng' phải 'bạn về cơ bản nói rằng không bao giờ nên có một lỗi" không rõ ràng? Bạn không nên sử dụng điều này trừ khi lỗi chỉ có thể do lập trình viên gây ra hoặc chương trình thực sự không thể tiếp tục nếu có lỗi. –

+1

Tôi không đồng ý với "hoặc chương trình thực sự không thể tiếp tục nếu có lỗi". Trong trường hợp đó bạn vẫn không nên hoảng sợ. –

24
func silly() (interface{}, error) { 
    return "silly", nil 
} 

v, err := silly() 
if err != nil { 
    // handle error 
} 

s, ok := v.(string) 
if !ok { 
    // the assertion failed. 
} 

nhưng nhiều khả năng những gì bạn thực sự muốn là sử dụng một công tắc loại, như-một-này:

switch t := v.(type) { 
case string: 
    // t is a string 
case int : 
    // t is an int 
default: 
    // t is some other type that we didn't name. 
} 

Go thực sự thêm về tính đúng đắn hơn là về terseness.

+0

Tuy nhiên tôi nghĩ rằng Go thành công trong việc khá ngắn gọn mà không từ bỏ sự chính xác. Đối với những người khác nhìn thấy câu hỏi này, tôi nghĩ rằng tốt là bạn đã đề cập đến việc kiểm tra xác nhận. Trong trường hợp của tôi mặc dù tôi đã biết những gì loại được lưu trữ trong giao diện, vì vậy tôi bỏ qua kiểm tra. Tôi thậm chí còn nghĩ về việc sử dụng một 'unsafe.Pointer' thay vì' interface {} ', nhưng tôi đoán không có đủ chi phí trong việc xác nhận kiểu xác minh việc sử dụng các con trỏ không an toàn. – ANisus

+1

Có lẽ tôi nên chỉ ra rằng cách thành ngữ để thực hiện điều này là không trả về giao diện {}, nhưng để chấp nhận giao diện {} làm tham số đầu vào, hãy kiểm tra loại đã được chuyển vào và sau đó điền vào loại đó. Điều này được minh họa khá độc đáo trong phương thức Unmarshal của gói mã hóa/json. Những kỹ thuật này không bao gồm tất cả các tình huống tương tự, do đó, nó có thể không phải lúc nào cũng có thể, nhưng nói chung là tốt hơn để chấp nhận giao diện {} hơn là trả về giao diện {}. Bạn có thể sử dụng gói phản ánh để kiểm tra để đảm bảo rằng giá trị được cung cấp là một con trỏ. – jorelli

2

Hoặc chỉ cần trong một đơn nếu:

if v, ok := value.(migrater); ok { 
    v.migrate() 
} 

Go sẽ chăm sóc của các diễn viên bên trong mệnh đề if và cho phép bạn truy cập vào các tính chất của loại đúc.