You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 14 Next »

数组容器,提供普通数组,及排序数组,支持数据项唯一性矫正,支持并发安全开关控制。

使用场景

数组操作。

使用方式

import "github.com/gogf/gf/container/garray"

接口文档

https://godoc.org/github.com/gogf/gf/container/garray

简要说明:

  1. garray模块下的对象及方法较多,建议仔细看看接口文档。
  2. garray支持int/string/interface{}三种常用的数据类型。
  3. garray支持普通数组和排序数组,普通数组的结构体名称定义为*Array格式,排序数组的结构体名称定义为Sorted*Array格式,如下:
    • Array, intArray, StrArray
    • SortedArray, SortedIntArray, SortedStrArray
    • 其中排序数组SortedArray,需要给定排序比较方法,在工具包gutil中也定义了很多Comparator*比较方法

以下示例主要展示一些常见数组用法,更多的方法请参考接口文档或源码。

普通数组

package main

import (
    "fmt"
    "github.com/gogf/gf/container/garray"
)


func main () {
    // 创建并发安全的int类型数组
    a := garray.NewIntArray(true)

    // 添加数据项
    for i := 0; i < 10; i++ {
        a.Append(i)
    }

    // 获取当前数组长度
    fmt.Println(a.Len())

    // 获取当前数据项列表
    fmt.Println(a.Slice())

    // 获取指定索引项
    fmt.Println(a.Get(6))

    // 在指定索引后插入数据项
    a.InsertAfter(9, 11)
    // 在指定索引前插入数据项
    a.InsertBefore(10, 10)
    fmt.Println(a.Slice())

    // 修改指定索引的数据项
    a.Set(0, 100)
    fmt.Println(a.Slice())

    // 搜索数据项,返回搜索到的索引位置
    fmt.Println(a.Search(5))

    // 删除指定索引的数据项
    a.Remove(0)
    fmt.Println(a.Slice())

    // 并发安全,写锁操作
    a.LockFunc(func(array []int) {
        // 将末尾项改为100
        array[len(array) - 1] = 100
    })

    // 并发安全,读锁操作
    a.RLockFunc(func(array []int) {
        fmt.Println(array[len(array) - 1])
    })

    // 清空数组
    fmt.Println(a.Slice())
    a.Clear()
    fmt.Println(a.Slice())
}

执行后,输出结果为:

10
[0 1 2 3 4 5 6 7 8 9]
6 true
[0 1 2 3 4 5 6 7 8 9 10 11]
[100 1 2 3 4 5 6 7 8 9 10 11]
5
[1 2 3 4 5 6 7 8 9 10 11]
100
[1 2 3 4 5 6 7 8 9 10 100]
[]

排序数组

排序数组的方法与普通数组类似,但是带有自动排序功能及唯一性过滤功能。

package main

import (
    "fmt"
    "github.com/gogf/gf/container/garray"
)


func main () {
    // 自定义排序数组,降序排序(SortedIntArray管理的数据是升序)
    a := garray.NewSortedArray(func(v1, v2 interface{}) int {
        if v1.(int) < v2.(int) {
            return 1
        }
        if v1.(int) > v2.(int) {
            return -1
        }
        return 0
    })

    // 添加数据
    a.Add(2)
    a.Add(3)
    a.Add(1)
    fmt.Println(a.Slice())

    // 添加重复数据
    a.Add(3)
    fmt.Println(a.Slice())

    // 检索数据,返回最后对比的索引位置,检索结果
    // 检索结果:0: 匹配; <0:参数小于对比值; >0:参数大于对比值
    fmt.Println(a.Search(1))

    // 设置不可重复
    a.SetUnique(true)
    fmt.Println(a.Slice())
    a.Add(1)
    fmt.Println(a.Slice())
}

执行后,输出结果:

[3 2 1]
[3 3 2 1]
3 0
[3 2 1]
[3 2 1]

Iterate*数组遍历

package main

import (
	"fmt"
	"github.com/gogf/gf/container/garray"
	"github.com/gogf/gf/frame/g"
)

func main() {
	array := garray.NewStrArrayFrom(g.SliceStr{"a", "b", "c"})
	// Iterator is alias of IteratorAsc, which iterates the array readonly in ascending order
	//  with given callback function <f>.
	// If <f> returns true, then it continues iterating; or false to stop.
	array.Iterator(func(k int, v string) bool {
		fmt.Println(k, v)
		return true
	})
	// IteratorDesc iterates the array readonly in descending order with given callback function <f>.
	// If <f> returns true, then it continues iterating; or false to stop.
	array.IteratorDesc(func(k int, v string) bool {
		fmt.Println(k, v)
		return true
	})

	// Output:
	// 0 a
	// 1 b
	// 2 c
	// 2 c
	// 1 b
	// 0 a
}

Pop*数组项出栈

package main

import (
	"fmt"
	"github.com/gogf/gf/container/garray"
)

func main() {
	array := garray.NewFrom([]interface{}{1, 2, 3, 4, 5, 6, 7, 8, 9})

	// Any Pop* functions pick, delete and return the item from array.

	fmt.Println(array.PopLeft())
	fmt.Println(array.PopLefts(2))
	fmt.Println(array.PopRight())
	fmt.Println(array.PopRights(2))

	// Output:
	// 1 true
	// [2 3]
	// 9 true
	// [7 8]
}

Rand/PopRand数组项随机获取/出栈

package main

import (
	"fmt"
	"github.com/gogf/gf/container/garray"
	"github.com/gogf/gf/frame/g"
)

func main() {
	array := garray.NewFrom(g.Slice{1, 2, 3, 4, 5, 6, 7, 8, 9})

	// Randomly retrieve and return 2 items from the array.
	// It does not delete the items from array.
	fmt.Println(array.Rands(2))

	// Randomly pick and return one item from the array.
	// It deletes the picked up item from array.
	fmt.Println(array.PopRand())
}

Contains/ContainsI包含判断

package main

import (
	"fmt"
	"github.com/gogf/gf/container/garray"
)

func main() {
	var array garray.StrArray
	array.Append("a")
	fmt.Println(array.Contains("a"))
	fmt.Println(array.Contains("A"))
	fmt.Println(array.ContainsI("A"))

	// Output:
	// true
	// false
	// true
}

FilterEmpty/FilterNil空值过滤

package main

import (
	"fmt"
	"github.com/gogf/gf/container/garray"
	"github.com/gogf/gf/frame/g"
)

func main() {
	array1 := garray.NewFrom(g.Slice{0, 1, 2, nil, "", g.Slice{}, "john"})
	array2 := garray.NewFrom(g.Slice{0, 1, 2, nil, "", g.Slice{}, "john"})
	fmt.Printf("%#v\n", array1.FilterNil().Slice())
	fmt.Printf("%#v\n", array2.FilterEmpty().Slice())

	// Output:
	// []interface {}{0, 1, 2, "", []interface {}{}, "john"}
	// []interface {}{1, 2, "john"}
}

Reverse数组翻转

package main

import (
	"fmt"
	"github.com/gogf/gf/container/garray"
	"github.com/gogf/gf/frame/g"
)

func main() {
	array := garray.NewFrom(g.Slice{1, 2, 3, 4, 5, 6, 7, 8, 9})

	// Reverse makes array with elements in reverse order.
	fmt.Println(array.Reverse().Slice())

	// Output:
	// [9 8 7 6 5 4 3 2 1]
}

Shuffle随机排序

package main

import (
	"fmt"
	"github.com/gogf/gf/container/garray"
	"github.com/gogf/gf/frame/g"
)

func main() {
	array := garray.NewFrom(g.Slice{1, 2, 3, 4, 5, 6, 7, 8, 9})

	// Shuffle randomly shuffles the array.
	fmt.Println(array.Shuffle().Slice())
}

Walk遍历修改

package main

import (
	"fmt"
	"github.com/gogf/gf/container/garray"
	"github.com/gogf/gf/frame/g"
)

func main() {
	var array garray.StrArray
	tables := g.SliceStr{"user", "user_detail"}
	prefix := "gf_"
	array.Append(tables...)
	// Add prefix for given table names.
	array.Walk(func(value string) string {
		return prefix + value
	})
	fmt.Println(array.Slice())

	// Output:
	// [gf_user gf_user_detail]
}

Join数组项串连

package main

import (
	"fmt"
	"github.com/gogf/gf/container/garray"
	"github.com/gogf/gf/frame/g"
)

func main() {
	array := garray.NewFrom(g.Slice{"a", "b", "c", "d"})
	fmt.Println(array.Join(","))

	// Output:
	// a,b,c,d
}

Chunk数组拆分

package main

import (
	"fmt"
	"github.com/gogf/gf/container/garray"
	"github.com/gogf/gf/frame/g"
)

func main() {
	array := garray.NewFrom(g.Slice{1, 2, 3, 4, 5, 6, 7, 8, 9})

	// Chunk splits an array into multiple arrays,
	// the size of each array is determined by <size>.
	// The last chunk may contain less than size elements.
	fmt.Println(array.Chunk(2))

	// Output:
	// [[1 2] [3 4] [5 6] [7 8] [9]]
}

Merge数组合并

package main

import (
	"fmt"
	"github.com/gogf/gf/container/garray"
	"github.com/gogf/gf/frame/g"
)

func main() {
	array1 := garray.NewFrom(g.Slice{1, 2})
	array2 := garray.NewFrom(g.Slice{3, 4})
	slice1 := g.Slice{5, 6}
	slice2 := []int{7, 8}
	slice3 := []string{"9", "0"}
	fmt.Println(array1.Slice())
	array1.Merge(array1)
	array1.Merge(array2)
	array1.Merge(slice1)
	array1.Merge(slice2)
	array1.Merge(slice3)
	fmt.Println(array1.Slice())

	// Output:
	// [1 2]
	// [1 2 1 2 3 4 5 6 7 8 9 0]
}

JSON序列化/反序列

garray模块下的所有容器类型均实现了标准库json数据格式的序列化/反序列化接口。

  1. Marshal 
package main
import ( "encoding/json" "fmt" "github.com/gogf/gf/container/garray" ) func main() { type Student struct { Id int Name string Scores *garray.IntArray } s := Student{ Id: 1, Name: "john", Scores: garray.NewIntArrayFrom([]int{100, 99, 98}), } b, _ := json.Marshal(s) fmt.Println(string(b)) }

执行后,输出结果:

 {"Id":1,"Name":"john","Scores":[100,99,98]} 


  1. Unmarshal
package main


import (
    "encoding/json"
    "fmt"
    "github.com/gogf/gf/container/garray"
)


func main() {
    b := []byte(`{"Id":1,"Name":"john","Scores":[100,99,98]}`)
    type Student struct {
        Id     int
        Name   string
        Scores *garray.IntArray
    }
    s := Student{}
    json.Unmarshal(b, &s)
    fmt.Println(s)
}

执行后,输出结果:

{1 john [100,99,98]} 


Append

  • 说明:向数组的尾部追加数据,可以添加任意数量字符串。Append的方法是PushRight的别名
  • 格式: 

    Append(value ...string) *StrArray
  • 示例:建立一个空数组,设置完数据后,并在数组尾部添加新的数据。

    func ExampleStrArray_Append() {
    	s := garray.NewStrArray()
    	s.SetArray(g.SliceStr{"We", "are", "GF", "fans"})
    	s.Append("a", "b", "c")
    	fmt.Println(s)
    
    	// Output:
    	// ["We","are","GF","fans","a","b","c"]
    }

At

  • 说明:返回数组指定索引的数据
  • 格式: 

    At(index int) (value string)
  • 示例:建立一个数组,找到index为2的数据。

    func ExampleStrArray_At() {
    	s := garray.NewStrArrayFrom(g.SliceStr{"We", "are", "GF", "fans", "!"})
    	sAt := s.At(2)
    	fmt.Println(sAt)
    
    	// Output:
    	// GF
    }

Chunk

  • 说明:把指定数组按指定的大小Size,分割成多个数组,返回值为[][]string。最后一个数组包含数据的数量可能小于Size
  • 格式: 

    Chunk(size int) [][]string
  • 示例:建立一个数组,并将该数组分割成3个数组。

    func ExampleStrArray_Chunk() {
    	s := garray.NewStrArrayFrom(g.SliceStr{"a", "b", "c", "d", "e", "f", "g", "h"})
    	r := s.Chunk(3)
    	fmt.Println(r)
    
    	// Output:
    	// [[a b c] [d e f] [g h]]
    }

Clear

  • 说明:删除当前数组中所有的数据
  • 格式: 

    Clear() *StrArray
  • 示例:建立一个空数组,赋值后,并删除该数组的数据。

    func ExampleStrArray_Clear() {
    	s := garray.NewStrArray()
    	s.SetArray(g.SliceStr{"a", "b", "c", "d", "e", "f", "g", "h"})
    	fmt.Println(s)
    	fmt.Println(s.Clear())
    	fmt.Println(s)
    
    	// Output:
    	// ["a","b","c","d","e","f","g","h"]
    	// []
    	// []
    }

Clone

  • 说明:克隆当前的数组。返回一个与当前数组相同的数组拷贝
  • 格式: 

    Clone() (newArray *StrArray)
  • 示例:建立一个空数组,赋值后,克隆出一个新数组。

    func ExampleStrArray_Clone() {
    	s := garray.NewStrArray()
    	s.SetArray(g.SliceStr{"a", "b", "c", "d", "e", "f", "g", "h"})
    	r := s.Clone()
    	fmt.Println(r)
    	fmt.Println(s)
    
    	// Output:
    	// ["a","b","c","d","e","f","g","h"]
    	// ["a","b","c","d","e","f","g","h"]
    }

Contains

  • 说明:判断一个数组是否包含给定的String值。字符串严格区分大小写。返回值为bool
  • 格式: 

    Contains(value string) bool
  • 示例:建立一个空数组,设置完数据后,判断是否包含指定数据ez

    func ExampleStrArray_Contains() {
    	s := garray.NewStrArray()
    	s.SetArray(g.SliceStr{"a", "b", "c", "d", "e", "f", "g", "h"})
    	fmt.Println(s.Contains("e"))
    	fmt.Println(s.Contains("z"))
    
    	// Output:
    	// true
    	// false
    }

ContainsI

  • 说明:判断一个数组是否包含给定的String值。字符串不区分大小写。返回值为bool
  • 格式: 

    ContainsI(value string) bool
  • 示例:建立一个空数组,设置完数据后,判断是否包含指定数据Ez

    func ExampleStrArray_ContainsI() {
    	s := garray.NewStrArray()
    	s.SetArray(g.SliceStr{"a", "b", "c", "d", "e", "f", "g", "h"})
    	fmt.Println(s.ContainsI("E"))
    	fmt.Println(s.ContainsI("z"))
    
    	// Output:
    	// true
    	// false
    }

CountValues

  • 说明:统计每个值在数组中出现的次数。返回值为map[string]int
  • 格式: 

    CountValues() map[string]int
  • 示例:建立一个数组,统计数组中每个字符串包含的个数

    func ExampleStrArray_CountValues() {
    	s := garray.NewStrArrayFrom(g.SliceStr{"a", "b", "c", "c", "c", "d", "d"})
    	fmt.Println(s.CountValues())
    
    	// Output:
    	// map[a:1 b:1 c:3 d:2]
    }

Fill

  • 说明:在数组中指定的开始位置startIndex,用指定的value进行填充。返回值为error
  • 格式: 

    Fill(startIndex int, num int, value string) error
  • 示例:建立一个数组,在数组开始位置index为2的地方,用字符串here填充3个数据

    func ExampleStrArray_Fill() {
    	s := garray.NewStrArrayFrom(g.SliceStr{"a", "b", "c", "d", "e", "f", "g", "h"})
    	s.Fill(2, 3, "here")
    	fmt.Println(s)
    
    	// Output:
    	// ["a","b","here","here","here","f","g","h"]
    }

FilterEmpty

  • 说明:过滤指定数组中的空字符串
  • 格式: 

    FilterEmpty() *StrArray
  • 示例:建立一个数组,在赋值后,过滤该数组中的空字符串

    func ExampleStrArray_FilterEmpty() {
    	s := garray.NewStrArrayFrom(g.SliceStr{"a", "b", "", "c", "", "", "d"})
    	fmt.Println(s.FilterEmpty())
    
    	// Output:
    	// ["a","b","c","d"]
    }

Get

  • 说明:返回数组中指定index的值,返回值有2个参数,返回值value,和是否找到指定位置的数据found,为true则找到,为false则未找到
  • 格式: 

    Get(index int) (value string, found bool) 
  • 示例:建立一个数组,在赋值后,得到数组index为3的值

    func ExampleStrArray_Get() {
    	s := garray.NewStrArrayFrom(g.SliceStr{"We", "are", "GF", "fans", "!"})
    	sGet, sBool := s.Get(3)
    	fmt.Println(sGet, sBool)
    
    	// Output:
    	// fans true
    }

InsertAfter

  • 说明:在数组中指定index的位置之后插入值value,返回值为error
  • 格式: 

    InsertAfter(index int, value string) error
  • 示例:建立一个数组,在index为1的值之后,插入字符串here

    func ExampleStrArray_InsertAfter() {
    	s := garray.NewStrArray()
    	s.SetArray(g.SliceStr{"a", "b", "c", "d"})
    	s.InsertAfter(1, "here")
    	fmt.Println(s.Slice())
    
    	// Output:
    	// [a b here c d]
    }

InsertBefore

  • 说明:在数组中指定index的位置之前插入值value,返回值为error
  • 格式: 

    InsertBefore(index int, value string) error
  • 示例:建立一个数组并初始化,在index为1的值之前,插入字符串here

    func ExampleStrArray_InsertBefore() {
    	s := garray.NewStrArray()
    	s.SetArray(g.SliceStr{"a", "b", "c", "d"})
    	s.InsertBefore(1, "here")
    	fmt.Println(s.Slice())
    
    	// Output:
    	// [a here b c d]
    }

Interfaces

  • 说明:把当前数组作为[]interface{}进行返回
  • 格式: 

    Interfaces() []interface{}
  • 示例:建立一个数组并初始化,并打印出返回值[]interface{}的内容

    func ExampleStrArray_Interfaces() {
    	s := garray.NewStrArray()
    	s.SetArray(g.SliceStr{"a", "b", "c", "d", "e", "f", "g", "h"})
    	r := s.Interfaces()
    	fmt.Println(r)
    
    	// Output:
    	// [a b c d e f g h]
    }

IsEmpty

  • 说明:判断当前数组是不是空数组,如果是空数组,则返回true,如果不是空数组,则返回false
  • 格式: 

    IsEmpty() bool
  • 示例:建立2个数组并初始化,并判断是否为空数组

    func ExampleStrArray_IsEmpty() {
    	s := garray.NewStrArrayFrom(g.SliceStr{"a", "b", "", "c", "", "", "d"})
    	fmt.Println(s.IsEmpty())
    	s1 := garray.NewStrArray()
    	fmt.Println(s1.IsEmpty())
    
    	// Output:
    	// false
    	// true
    }

Iterator

  • 说明:数组遍历
  • 格式: 

    Iterator(f func(k int, v string) bool)
  • 示例:建立1个数组,并对其进行遍历

    func ExampleStrArray_Iterator() {
    	s := garray.NewStrArrayFrom(g.SliceStr{"a", "b", "c"})
    	s.Iterator(func(k int, v string) bool {
    		fmt.Println(k, v)
    		return true
    	})
    
    	// Output:
    	// 0 a
    	// 1 b
    	// 2 c
    }

IteratorAsc

  • 说明:根据给定的回调函数f,按升序对数组进行遍历,如果f返回true,则继续进行遍历,否则停止遍历
  • 格式: 

    IteratorAsc(f func(k int, v string) bool)
  • 示例:建立1个数组,并按照自定义函数对其进行升序遍历

    func ExampleStrArray_Iterator() {
    	s := garray.NewStrArrayFrom(g.SliceStr{"a", "b", "c"})
    	s.Iterator(func(k int, v string) bool {
    		fmt.Println(k, v)
    		return true
    	})
    
    	// Output:
    	// 0 a
    	// 1 b
    	// 2 c
    }

IteratorDesc

  • 说明:根据给定的回调函数f,按降序对数组进行遍历,如果f返回true,则继续进行遍历,否则停止遍历
  • 格式: 

    IteratorAsc(f func(k int, v string) bool)
  • 示例:建立1个数组,并按照自定义函数对其进行降序遍历

    func ExampleStrArray_IteratorDesc() {
    	s := garray.NewStrArrayFrom(g.SliceStr{"a", "b", "c"})
    	s.IteratorDesc(func(k int, v string) bool {
    		fmt.Println(k, v)
    		return true
    	})
    
    	// Output:
    	// 2 c
    	// 1 b
    	// 0 a
    }

Join

  • 说明:将数组元素根据给定的字符串连接符gule,连接起来
  • 格式: 

    Join(glue string) string
  • 示例:给定连接符',',将数组中的字符串连接起来

    func ExampleStrArray_Join() {
    	s := garray.NewStrArrayFrom(g.SliceStr{"a", "b", "c"})
    	fmt.Println(s.Join(","))
    
    	// Output:
    	// a,b,c
    }

Len

  • 说明:得到数组的长度
  • 格式: 

    Join(glue string) string
  • 示例:建立一个新数组,初始化后得到该数组的长度

    func ExampleStrArray_Len() {
    	s := garray.NewStrArray()
    	s.SetArray(g.SliceStr{"a", "b", "c", "d", "e", "f", "g", "h"})
    	fmt.Println(s.Len())
    
    	// Output:
    	// 8
    }

LockFunc

  • 说明:通过回调函数f对数组进行写锁定
  • 格式: 

    LockFunc(f func(array []string)) *StrArray 
  • 示例:建立一个新数组,并对该数组在写锁定的状态下,修改最后一个数据

    func ExampleStrArray_LockFunc() {
    	s := garray.NewStrArrayFrom(g.SliceStr{"a", "b", "c"})
    	s.LockFunc(func(array []string) {
    		array[len(array)-1] = "GF fans"
    	})
    	fmt.Println(s)
    
    	// Output:
    	// ["a","b","GF fans"]
    }

MarshalJSON

  • 说明:实现json.MarshalJSON格式的序列化接口
  • 格式: 

    MarshalJSON() ([]byte, error)
  • 示例:建立一个新JSON格式的数据,并对该数据进行序列化的操作后,打印出相应结果

    func ExampleStrArray_MarshalJSON() {
    	type Student struct {
    		Id      int
    		Name    string
    		Lessons []string
    	}
    	s := Student{
    		Id:      1,
    		Name:    "john",
    		Lessons: []string{"Math", "English", "Music"},
    	}
    	b, _ := json.Marshal(s)
    	fmt.Println(string(b))
    
    	// Output:
    	// {"Id":1,"Name":"john","Lessons":["Math","English","Music"]}
    }

Merge

  • 说明:合并数组,将指定数组中的内容合并到当前数组中。参数array可以是任意garrayslice类型。MergeAppend的主要区别是Append仅仅支持slice类型,Merge则支持更多的参数类型
  • 格式: 

    Merge(array interface{}) *StrArray
  • 示例:建立2个新数组s1s2,并将s2的数据合并到s1

    func ExampleStrArray_Merge() {
    	s1 := garray.NewStrArray()
    	s2 := garray.NewStrArray()
    	s1.SetArray(g.SliceStr{"a", "b", "c"})
    	s2.SetArray(g.SliceStr{"d", "e", "f"})
    	s1.Merge(s2)
    	fmt.Println(s1)
    
    	// Output:
    	// ["a","b","c","d","e","f"]
    }

Pad

  • 说明:填充指定大小为size的值value到数组中。如果大小size是正数,则从数组的右边开始填充。如果size是负数,则从数组的左边开始填充。如果size的大小正好等于数组的长度,那么将不会填充任何数据。
  • 格式: 

    Pad(size int, value string) *StrArray
  • 示例:建立1个新数组,先从左边将数组,用指定的字符串here填充到size为7,然后用指定的字符串there将数组用字符串填充到size为10

    func ExampleStrArray_Pad() {
    	s := garray.NewStrArrayFrom(g.SliceStr{"a", "b", "c"})
    	s.Pad(7, "here")
    	fmt.Println(s)
    	s.Pad(-10, "there")
    	fmt.Println(s)
    
    	// Output:
    	// ["a","b","c","here","here","here","here"]
    	// ["there","there","there","a","b","c","here","here","here","here"]
    }





NewStrArray

  • 格式: NewStrArray:safe
  • 说明:非必需参数,Safe为布尔型参数,是并发安全的开关,缺省值为False
  • 示例:建立一个空数组,并添加数据。此时没有指定 Safe参数,默认为非并发安全设置

    func ExampleNewStrArray() {
    	s := garray.NewStrArray()
    	s.Append("We")
    	s.Append("are")
    	s.Append("GF")
    	s.Append("Fans")
    	fmt.Println(s.Slice())
    	
    	// Output:
    	// [We are GF Fans]
    }


Content Menu

  • No labels