2016-07-22 2 views
3

의 내가 조각 나는 직관적으로 쓰고 싶은Go에서 슬라이스로 제네릭 함수를 만들려면 어떻게해야합니까?

에 값을 찾는 함수를 작성하고 싶은 말은하자

func find(s []interface{}, f func(interface{})bool) int { 
    for i, item := range s { 
     if f(item) { 
      return i 
     } 
    } 
    return -1 
} 

그러나 나는 이동이 작업을 수행하기 위해 관리하지 않습니다. , ... 등 추가 내가 재정의하는 경우 : 나는

Len() int 
Value(int) interface{} 
... 

과의 인터페이스를 가질 수 이것은 작동합니다하지만 내 실제 코드에서 가지 (등 내가 [끝에서] 조각을 할 필요가) 더 복잡 이 모든 것을 하나의 인터페이스에두면 많은 코드가 생깁니다. 더 좋은 방법이 있습니까?

+1

대답은 제네릭이지만 제네릭은 사용하지 않습니다. 따라서 효과적으로 리플렉션을 사용하고 * n * find_ [type] 함수를 작성하거나 모든 곳에서 인터페이스를 사용하여 걸어 다녀야합니다. 지금까지는별로 즐겁지 않습니다. – Jakumi

+0

배열에 어떤 영향이 있습니까? 그것들은 임의의 값입니까, 아니면 비교할 필요가있는 특정 유형입니까? –

+0

@squint 배열은 "표준"입니다. 배열 [] A 배열과 [] B 배열 (모든 구조체, 인터페이스가 아님) – Thomas

답변

1

리플렉션을 사용할 수 있습니다. 나는이 프로젝트에 대해이 기능을 작성, 사용 주시기 :

// InSlice returns true if value is in slice 
func InSlice(value, slice interface{}) bool { 
    switch reflect.TypeOf(slice).Kind() { 
    case reflect.Slice, reflect.Ptr: 
     values := reflect.Indirect(reflect.ValueOf(slice)) 
     if values.Len() == 0 { 
      return false 
     } 

     val := reflect.Indirect(reflect.ValueOf(value)) 

     if val.Kind() != values.Index(0).Kind() { 
      return false 
     } 

     for i := 0; i < values.Len(); i++ { 
      if reflect.DeepEqual(values.Index(i).Interface(), val.Interface()) { 
       return true 
      } 
     } 
    } 
    return false 
} 
1

당신은 []int 또는 []string 같은 미리 정의 된 유형을 가지고 (reflect를 사용하지 않고)이 작업 예제 코드를 볼 []interface{}로 변환하지 않으려는 경우 :

package main 

import "fmt" 

func find(s []int, f func(int) bool) int { 
    for i, item := range s { 
     if f(item) { 
      return i 
     } 
    } 
    return -1 
} 
func findString(s []string, f func(string) bool) int { 
    for i, item := range s { 
     if f(item) { 
      return i 
     } 
    } 
    return -1 
} 

func main() { 
    s := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} 
    fmt.Println(find(s, func(a int) bool { return a == 5 })) //5 

    strs := []string{"A", "B", "C"} 
    fmt.Println(findString(strs, func(a string) bool { return a == "B" })) //1 
} 

또는이 작업의 샘플 코드와 같은 reflect를 사용할 수있다 :

package main 

import "fmt" 
import "reflect" 

func find(slice interface{}, f func(interface{}) bool) int { 
    switch reflect.TypeOf(slice).Kind() { 
    case reflect.Slice: 
     values := reflect.Indirect(reflect.ValueOf(slice)) 
     for i := 0; i < values.Len(); i++ { 
      if f(values.Index(i).Interface()) { 
       return i 
      } 
     } 
    } 
    return -1 
} 

func main() { 
    a := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} 
    fmt.Println(find(a, func(i interface{}) bool { return i == 5 })) //5 

    b := []string{"A", "B", "C"} 
    fmt.Println(find(b, func(i interface{}) bool { return i == "B" })) //1 
} 

출력 :

5 
1 
,536,

도움이되기를 바랍니다.

+0

감사하지만 이미 2 개의 배열이 있습니다 : a : = A [] {} 및 b : = B [] {} 어떻게합니까? 이 경우에 당신이 제안한 것은 무엇입니까? find (a, fa)와 find (b, fb)는 호출 할 수 없습니다. (나는 그것을 복사하는 것을 피하기 위해 함수를 찾는다.) – Thomas

+0

고마워,하지만 지금은 위의 답이다. :) 근데 고마워. +1. 답안의 마지막 부분 만 지키고 싶다면, 최선이며 일을 좀 더 읽기 좋게 만들어야합니다. – Thomas

0

당신이 임의의 값의 조각을 가지고 find 기능의 종류를 사용하고 [] 표준 reslicing의 가능성을 갖고 싶어 내가 어쩌면, 생각 가장 좋은 방법은 다른 구조체

type proxy struct { 
    val interface{} 
} 

interface{}을 캡슐화하고

func find(s []proxy , f func(proxy)bool) int {} 

를 사용하고 근래하는 것입니다 e f 함수는 interface{} 비교/유형 캐스팅을 처리합니다.

+0

고마워요. 그러나 이것은 제 배열을 [] 프록시로 복사하도록 강요합니다. 하지만 가치가있을 수도 있습니다. – Thomas

+0

이 솔루션을 이해할 수 없습니다. 왜 [[] proxy가'[] interface {}'보다 나은가요? –

+0

@PaulHankin Go는 [] inteface {} 인수가있을 때 [] A를 전달할 때 컴파일되지 않습니다. – Thomas