構造体内に別構造体の配列を定義して、その配列がネストしていくようなイメージのものを作って再帰的に値を取り出してみたかったので試してみました。
イメージ
やりたかったのは、配列の中に配列が...さらに配列が...のようなイメージのものをやってみたかった。
pythonで言うと以下のようなイメージ(ざっくり感がパない)
# !/usr/bin/env python3
array = [1, 2, 3]
array2 = [4, 5, 6]
array3 = [7,8,9]
array2.append(array3)
array.append(array2)
print(array)
def rec(a):
for i in a:
if(isinstance(i, list)):
rec(i)
else:
print(i)
for i in array:
if(isinstance(i, list)):
rec(i)
else:
print(i)
これを実行すると以下のような結果になります。
classを作ってやったほうがイメージが近いのではと思いましたがめんd
$ ./example.py
[1, 2, 3, [4, 5, 6, [7, 8, 9]]]
1
2
3
4
5
6
7
8
9
ようは、配列の要素を一つずつ取り出して行ってもし配列型だった場合は再度forを回して再帰的に値を取得していくものがGoで実装したかった!!
使用する構造体について
ここでは Test
と ChildTests
の構造体を例にしてみたいと思います。
Testの Nameフィールド
で定義した名前を親にして、それの子を ChildTestsフィールド
に定義していく形にします。
type Test struct {
Name string
ChildTests []ChildTests
}
type ChildTests struct {
Name string
ChildTests []ChildTests
}
ChildTests構造体の ChildTestsフィールド
は自身のスライスを定義しているので以下のようにネストするような実装が可能になります。
s := []Test{
Test{
Name: "HOGE",
ChildTests: []ChildTests{
ChildTests{
Name: "FUGA",
ChildTests: []ChildTests{
ChildTests{
Name: "HIGE",
},
},
},
},
},
}
実装例
親には HOGE
と Taro
を指定して、それぞれの子を設定して実行してみます。
Test構造体
のスライスを作って RecursiveCall
関数に渡して子が1個以上ある場合は GetChild
に渡して再帰的に値を取得しています。
GetChild
の引数は interface
として受け取って reflect
を駆使してやってみました。。。
package main
import (
"fmt"
"reflect"
)
type Test struct {
Name string
ChildTests []ChildTests
}
type ChildTests struct {
Name string
ChildTests []ChildTests
}
func GetChild(ts interface{}, c int) {
s := reflect.ValueOf(ts)
v := reflect.Indirect(s.Index(0))
t := v.Type()
for i := 0; i < t.NumField(); i++ {
if t.Field(i).Name == "Name" {
c += 2
for i := 0; i < c; i++ {
fmt.Print(" ")
}
fmt.Println(v.Field(i).String())
}
if t.Field(i).Name == "ChildTests" && v.Field(i).Len() > 0 {
GetChild(v.Field(i).Interface(), c)
}
}
}
func RecursiveCall(t []Test) {
for _, i := range t {
fmt.Println(i.Name)
if len(i.ChildTests) >= 1 {
GetChild(i.ChildTests, 0)
}
}
}
func main() {
s := []Test{
Test{
Name: "HOGE",
ChildTests: []ChildTests{
ChildTests{
Name: "FUGA",
ChildTests: []ChildTests{
ChildTests{
Name: "HIGE",
ChildTests: []ChildTests{
ChildTests{
Name: "HHH",
},
},
},
},
},
},
},
Test{
Name: "Taro",
ChildTests: []ChildTests{
ChildTests{
Name: "Hanako",
},
},
},
}
RecursiveCall(s)
}
実行結果
子がある場合は、スペースでインデントを入れています。
$ go run main.go
HOGE
FUGA
HIGE
HHH
Taro
Hanako
今回は、結構力任せでやっていますが期待していたことが出来たのでひとまずこれでよしとしよう。。。