2011-08-09 23 views
32

Tôi có vài chức năng C tuyên bố như thế nàyLàm thế nào để kiểm tra kiểu dữ liệu trong thời gian chạy bằng ngôn ngữ Go

CURLcode curl_wrapper_easy_setopt_long(CURL* curl, CURLoption option, long param); 
CURLcode curl_wrapper_easy_setopt_str(CURL* curl, CURLoption option, char* param); 

Tôi muốn để lộ những là một Go chức năng như thế này

func (e *Easy)SetOption(option Option, param interface{}) 

vì vậy tôi cần để có thể kiểm tra thông số khi chạy. Làm thế nào để làm điều đó và là ý tưởng tốt này (nếu không phải là thực hành tốt trong trường hợp này) là gì?

Trả lời

11

Xem loại khẳng định đây:

http://golang.org/ref/spec#Type_assertions

Tôi muốn khẳng định một loại nhạy cảm (string, uint64) chỉ vv và giữ nó như lỏng càng tốt, thực hiện chuyển đổi sang các loại có nguồn gốc cuối cùng.

+9

Câu trả lời phải hoàn tất, không chỉ liên kết. Vui lòng đưa ra câu trả lời này. – Flimzy

+2

Lưu ý: Tính năng này không hoạt động đối với các loại bê tông, chỉ có các loại giao diện. – darethas

-1

Có gì sai với

func (e *Easy)SetStringOption(option Option, param string) 
func (e *Easy)SetLongOption(option Option, param long) 

và vân vân?

+0

vì trong thư viện C libCURL chỉ có một hàm để thiết lập tùy chọn curl_easy_setopt (CURL * curl, tùy chọn CURLoption, ...). Nhưng cgo không hỗ trợ varargs vì vậy tôi đã thực hiện hàm wrapper trong C cho mỗi kiểu tham số. Tôi nghĩ rằng giao diện Go nên càng gần C càng tốt. Nếu người dùng biết libCURL (từ C hoặc ngôn ngữ khác) tôi muốn anh ấy cảm thấy như ở nhà;) –

+0

Muộn với trò chơi, nhưng tôi muốn tranh luận chống lại cách tiếp cận đó! Bạn muốn thư viện cảm thấy như ở nhà với người dùng * Go *. (Ví dụ tốt nhất về nơi các cổng trực tiếp của các thư viện cấp thấp hơn như cURL nhầm lẫn mọi người là ... PHP) – Nevir

47

Dường như Go có hình thức đặc biệt của công tắc dành cho điều này (nó được gọi là loại switch):

func (e *Easy)SetOption(option Option, param interface{}) { 

    switch v := param.(type) { 
    default: 
     fmt.Printf("unexpected type %T", v) 
    case uint64: 
     e.code = Code(C.curl_wrapper_easy_setopt_long(e.curl, C.CURLoption(option), C.long(v))) 
    case string: 
     e.code = Code(C.curl_wrapper_easy_setopt_str(e.curl, C.CURLoption(option), C.CString(v))) 
    } 
} 
+0

Cú pháp này chỉ có thể được sử dụng trong 'chuyển'? Ví dụ, nếu tôi chỉ quan tâm đến 1 trường hợp có thể một công tắc là quá mức cần thiết? –

+0

@NathanH Vâng, cách này chỉ hoạt động cho chuyển đổi (được thử nghiệm với Go 1.10) – MewX

36

Câu trả lời bởi @Darius là phương pháp thành ngữ nhất (và có lẽ hơn performant). Một hạn chế là loại bạn đang kiểm tra phải thuộc loại interface{}. Nếu bạn sử dụng một loại bê tông nó sẽ thất bại.

Một cách khác để xác định loại thứ gì đó trong thời gian chạy, bao gồm các loại cụ thể, là sử dụng gói Go reflect. Loạt TypeOf(x).Kind() cùng bạn có thể nhận được một giá trị reflect.Kind mà là một loại uint: http://golang.org/pkg/reflect/#Kind

Sau đó bạn có thể thực hiện kiểm tra đối với các loại bên ngoài của một khối chuyển đổi, như vậy:

import (
    "fmt" 
    "reflect" 
) 

// .... 

x := 42 
y := float32(43.3) 
z := "hello" 

xt := reflect.TypeOf(x).Kind() 
yt := reflect.TypeOf(y).Kind() 
zt := reflect.TypeOf(z).Kind() 

fmt.Printf("%T: %s\n", xt, xt) 
fmt.Printf("%T: %s\n", yt, yt) 
fmt.Printf("%T: %s\n", zt, zt) 

if xt == reflect.Int { 
    println(">> x is int") 
} 
if yt == reflect.Float32 { 
    println(">> y is float32") 
} 
if zt == reflect.String { 
    println(">> z is string") 
} 

nào in outs:

reflect.Kind: int 
reflect.Kind: float32 
reflect.Kind: string 
>> x is int 
>> y is float32 
>> z is string 

Một lần nữa, đây có lẽ không phải là cách ưu tiên để làm điều đó, nhưng tốt nhất là nên biết các tùy chọn thay thế.

+0

Tại sao bạn cần '.Kind()'? Nó hoạt động mà không có nó. – karantan

+0

@karantan Theo mã của quux00 .Kind() là cần thiết. Nếu không, bạn sẽ nhận được lỗi thời gian biên dịch. https://golang.org/pkg/reflect/#Kind Loại A thể hiện loại loại cụ thể mà Loại đại diện cho https://golang.org/pkg/reflect/#TypeOf giao diện kiểu trả về {} – Mujibur

0

Câu trả lời của quux00 chỉ cho biết về việc so sánh các loại cơ bản.

Nếu bạn cần so sánh các loại bạn đã xác định, bạn không nên sử dụng reflect.TypeOf(xxx). Thay vào đó, hãy sử dụng reflect.TypeOf(xxx).Kind().

Có hai loại của các loại:

  • loại trực tiếp (các loại bạn định nghĩa trực tiếp)
  • loại cơ bản (int, float64, struct, ...)

Đây là một ví dụ đầy đủ:

type MyFloat float64 
type Vertex struct { 
    X, Y float64 
} 

type EmptyInterface interface {} 

type Abser interface { 
    Abs() float64 
} 

func (v Vertex) Abs() float64 { 
    return math.Sqrt(v.X*v.X + v.Y*v.Y) 
} 

func (f MyFloat) Abs() float64 { 
    return math.Abs(float64(f)) 
} 

var ia, ib Abser 
ia = Vertex{1, 2} 
ib = MyFloat(1) 
fmt.Println(reflect.TypeOf(ia)) 
fmt.Println(reflect.TypeOf(ia).Kind()) 
fmt.Println(reflect.TypeOf(ib)) 
fmt.Println(reflect.TypeOf(ib).Kind()) 

if reflect.TypeOf(ia) != reflect.TypeOf(ib) { 
    fmt.Println("Not equal typeOf") 
} 
if reflect.TypeOf(ia).Kind() != reflect.TypeOf(ib).Kind() { 
    fmt.Println("Not equal kind") 
} 

ib = Vertex{3, 4} 
if reflect.TypeOf(ia) == reflect.TypeOf(ib) { 
    fmt.Println("Equal typeOf") 
} 
if reflect.TypeOf(ia).Kind() == reflect.TypeOf(ib).Kind() { 
    fmt.Println("Equal kind") 
} 

Kết quả sẽ là:

main.Vertex 
struct 
main.MyFloat 
float64 
Not equal typeOf 
Not equal kind 
Equal typeOf 
Equal kind 

Như bạn thấy, reflect.TypeOf(xxx) trả về loại trực tiếp mà bạn có thể muốn sử dụng, trong khi reflect.TypeOf(xxx).Kind() trả về các loại cơ bản.


Đây là kết luận. Nếu bạn cần so sánh với các loại cơ bản, hãy sử dụng reflect.TypeOf(xxx).Kind(); và nếu bạn cần so sánh với các loại tự định nghĩa, hãy sử dụng reflect.TypeOf(xxx).

if reflect.TypeOf(ia) == reflect.TypeOf(Vertex{}) { 
    fmt.Println("self-defined") 
} else if reflect.TypeOf(ia).Kind() == reflect.Float64 { 
    fmt.Println("basic types") 
} 
Các vấn đề liên quan