2017-11-28 16 views
1

지도에서 직접 값을 탐색하고 싶습니다. (https://play.golang.org/p/tYJsvp39hn)golang의 문자열 경로 변수를 사용하여지도로 이동

type Signature struct{ 
    Name string 
    Signed bool 
}  

path := "Document.Signatures.1.Name" 
map := map[string]interface{}{ 
    "Document": map[string]interface{}{ 
     "Signatures": []interface{}{ 
      Signature{ Name: "Hugo", Signed: false }, 
      Signature{ Name: "Walter", Signed: false }, 
     }, 
     "Otherstuff": "asadwa", 
    }, 
    "AlsoOtherStuff": "adwaw", 
} 

// map.giveMe(path) 
// even better (if possible:) map.change(path,"ToThisNewValue") 

내가 솔루션을 검색했지만, 인터넷에 어떤을 찾을 수 없습니다 : 나에게 직접 '월터'의 값을 제공해야 다음 이동 코드 예제 더 구체적으로 할 수 있습니다. 어쩌면 당신 중 하나가 이것을하는 방법을 알고 있거나 나를 위해 사용할 라이브러리를 알고있을 것입니다.

미리 감사드립니다.

+1

당신은 점점이 답변에 경로에 의해 주어진 요소 설정의 예를 볼 수있다 : [JSON 문자열을 복용지도, 편집으로 비 정렬 화하고, 바이트로 마샬링을 더 복잡해 보인다] (https://stackoverflow.com/questions/28877512/taking-a-json-string-unmarshaling-it-a-a-mapstringinterface-editing-an#28878037) (차이점은 경로는 문자열 슬라이스로 제공되지만 개념은 동일합니다. – icza

+0

빠른 답장을 보내 주셔서 감사합니다. 내 값을 비 정렬 화하기 위해 미리 정의 된 구조체가있는 경우. Selectors (구조체 유형의 경우) 및 인덱스 표현식 (지도 및 슬라이스의 경우)을 사용하여 탐색 할 수 있습니까? 여러 단계로 이동하려는 경우에도 가능합니까? 내 질문에 대한 답변을 희망 하시길 바랍니다. –

+0

당신은 할 수 있지만 반성이 필요하다면 ('reflect' 패키지), 내 보낸 필드에서만 작동합니다. – icza

답변

2

미리 정의 된 구조체가 없으면 상당히 많은 반사 호출이 필요합니다.

즉, 모든 반복에서 유형 검사 및 그에 따른 사례 처리를 통해 맵을 반복하여 수행 할 수 있습니다.

// Splitting the path into keys 
keys := strings.Split(path, ".") 

var value interface{} = map1 
for _, key := range keys { 
    if value, err = Get(key, value); err != nil { 
     break 
    } 
} 
if err == nil { 
    fmt.Println("Value:", value) 
} else { 
    fmt.Println("Error:", err) 
} 


func Get(key string, s interface{}) (v interface{}, err error) { 
    var (
     i int64 
     ok bool 
    ) 
    switch s.(type) { 
    case map[string]interface{}: 
     if v, ok = s.(map[string]interface{})[key]; !ok { 
      err = fmt.Errorf("Key not present. [Key:%s]", key) 
     } 
    case []interface{}: 
     if i, err = strconv.ParseInt(key, 10, 64); err == nil { 
      array := s.([]interface{}) 
      if int(i) < len(array) { 
       v = array[i] 
      } else { 
       err = fmt.Errorf("Index out of bounds. [Index:%d] [Array:%v]", i, array) 
      } 
     } 
    case Signature: 
     r := reflect.ValueOf(s) 
     v = reflect.Indirect(r).FieldByName(key) 
    } 
    //fmt.Println("Value:", v, " Key:", key, "Error:", err) 
    return v, err 
} 

Playground code