2013-08-07 4 views
5

में सामान्य कार्यों को लागू करने के कहते हैं कि मैं जांच के लिए एक विधेय एक टुकड़ा में एक तत्व के लिए मिलान किया जाता है कि क्या एक समारोह लिखने के लिए चाहते हैं:मुहावरेदार रास्ता तय

func IsIn(array []T, pred func(elt T) bool) bool { 
    for _, obj := range array { 
     if pred(obj) { return true;} 
    } 
    return false; 
} 

जाहिर है, पिछले कोड संकलन नहीं होगा, चूंकि T मौजूद नहीं है। जो नहीं है

IsIn([]interface{}{1,2,3,4}, func(o interface{}) {return o.(int) == 3; }); 

लेकिन फिर भी, समारोह किसी भी सरणी स्वीकार नहीं करेंगे:

func IsIn(array[]interface{}, pred func(elt interface{}) bool) bool { 
    ... 
} 

मैं विधेय कास्टिंग प्रदर्शन करते हुए खुशी हो रही के रूप में: मैं इस तरह कुछ interface{} साथ यह जगह ले सकता है के प्रकार []interface{}:

IsIn([]int{1,2,3,4}, func(o interface{}) { return o.(int) == 3; }) // DO NOT COMPILE 

और इसी तरह:

func IsIn(arr interface, pred func(o interface{}) bool) bool { 
    for _, o := range arr.([]interface{}) { ... } 
} 
IsIn([]int{1,2,3,4}, func(o interface{}) { return o.(int) == 3; }) // PANICS AT RUNTIME (cannot cast []int to []interface) 

अन्य वैकल्पिक प्रत्येक सरणी प्रकार के लिए काम करता है टाइप किया है के लिए है:

IsInInt(arr []int, pred func(i int) bool) { ... } 
IsInStr(arr []string, pred func(s string) bool) { ... } 
... 

लेकिन यह कोड दोहराव की एक बहुत की तरह लगता है।

क्या कोई ऐसी स्थितियों से निपटने के लिए एक अच्छा तरीका है?

संपादित

jnml के लिए धन्यवाद 'गो प्रतिबिंब पर रों शानदार टिप्स, मुझे लगता है कि मैं इन पैटर्न व्यक्त करने के लिए एक अच्छा तरीका, परिवर्तित करके पाया है कि हर' iterable 'ने चैनल के लिए:

func iter(obj interface{}) chan interface{} { 
    c := make(chan interface{}) 
    v := reflect.ValueOf(obj) 
    if (v.Kind() == reflect.Array || v.Kind() == reflect.Slice) { 
     go func() { 
      for i := 0; i < v.Len(); i++ { 
       c<-v.Index(i).Interface() 
      } 
      close(c) 
     }() 
    } else if v.Kind() == reflect.Chan { 
     go func() { 
      x, ok := v.Recv() 
      for ok { 
       c<-x.Interface() 
       x,ok = v.Recv() 
      } 
      close(c) 
     }() 
    } else if (... whatever iteration protocol you have ...) { 
    } else { 
     panic("Cannot iterate !") 
    } 
    return c; 
} 

मेरे प्रारंभिक उदाहरण के साथ on the playground का उपयोग करके पुनः लिखा गया।

मदद करने के लिए jnml और ANisus पर बहुत कुछ धन्यवाद!

उत्तर

4

उदाहरण के लिए पाया जा सकता है:

package main 

import (
     "fmt" 
     "reflect" 
) 

func checkSlice(slice interface{}, predicate func(reflect.Value) bool) bool { 
     v := reflect.ValueOf(slice) 
     if v.Kind() != reflect.Slice { 
       panic("not a slice") 
     } 

     for i := 0; i < v.Len(); i++ { 
       if predicate(v.Index(i)) { 
         return true 
       } 
     } 

     return false 
} 

func main() { 
     a := []int{1, 2, 3, 4, 42, 278, 314} 
     fmt.Println(checkSlice(a, func(v reflect.Value) bool { return v.Int() == 42 })) 

     b := []float64{1.2, 3.4, -2.5} 
     fmt.Println(checkSlice(b, func(v reflect.Value) bool { return v.Float() > 4 })) 
} 

Playground


आउटपुट:

true 
false 
+0

अच्छा! वह चाल है। मुझे उस भाषा का यह हिस्सा दिखाने के लिए धन्यवाद जो मुझे नहीं पता था :) – val

3

मैं यह नहीं कह सकता कि यह है बेवकूफ। लेकिन एक आदर्श समाधान sort पैकेज में करना होगा; सरणी के लिए एक इंटरफेस को परिभाषित करने के:

type Interface interface { 
    Len() int 
    Equal(i int, v interface{}) bool 
} 

func IsIn(array Interface, value interface{}) bool { 
    for i := 0; i < array.Len(); i++ { 
    if array.Equal(i, value) { 
      return true 
     } 
    } 
    return false; 
} 

जब तक आपके सरणी इस इंटरफेस को लागू करता है, तब तक आप ISIN उपयोग कर सकते हैं()।

कार्य उदाहरण वह here

संबंधित मुद्दे