Slices
Before we go over structs, which are the most common data type when sending and receiving information between applications (back-end to front-end, front-end to back-end, or back-end to websites, etc.), and this is especially true when interacting with the Algorand blockchain, I think it's important to have an understanding of how slices work.
Below is an example of a slice:
var mySlice = []interface{}{7, "Hello", false, 63.5}
A slice can hold all types of data, and you can have all kinds of data in one slice. You use slices when you need exactly that, a list. Slices are also mutable, which means we can rearrange, extend, and replace items in a slice, meaning they're super flexible!
A slice is a collection of data enclosed between square brackets [ ], and separated by commas. An example of common kinds of data you would have in a slice on Algorand could be one that has asset IDs.
var assetIDs = []int{1265975021, 1138500612, 400593267}
Or perhaps a slice of addresses:
var addresses = [
"WWYUMYPM2Y5NIIZTF4O5N73A4ZTZQWXS6TNP23U37LQ6WWF543SRTGKWUU",
"7IWZ342UGNQ2JVS2E6EGFD4MPUNL4ZIWDYNFZIANR6U7WZXORCRQCCN3YY",
"HZ57J3K46JIJXILONBBZOHX6BKPXEM2VVXNRFSUED6DKFD5ZD24PMJ3MVA"];
Although slices don't have to be organized in any way and are not descriptive, they can be manipulated. For example, if you wanted to remove duplicate entries in a slice, you could use a map to achieve this.
func removeDuplicates(elements []int) []int {
encountered := map[int]bool{};
result := []int{};
for v := range elements {
if encountered[elements[v]] != true {
encountered[elements[v]] = true;
result = append(result, elements[v]);
}
}
return result;
}
mySlice := []int{1, 1, 2, 3, 4, 4};
mySliceWithoutDuplicates := removeDuplicates(mySlice);
fmt.Println(mySliceWithoutDuplicates);
# Output: [1, 2, 3, 4]
Let's look back at the first example of a slice:
mySlice = []interface{}{7, "Hello", false, 63.5}
In the slice above we have an integer at the first spot, 7; a string in the second spot, "Hello"; a boolean (true or false value) in the third spot; a float (decimal value), in the fourth spot. I refer to the places these items are in the slice as "spots", but the correct term is actually "indexes". We referenced them as the first, second, third, and fourth spot— however, in programming slices are zero-indexed. This means that we always start from zero, and use an integer to refer to their position in the slice. This feels strange, but it is something you should have ingrained into your mind, as this is universal across all programming when indexing for positions in a slice.
The correct reference to the positions would be Index 0 for 7, Index 1 for "Hello", Index 2 for false, and Index 3 for 63.5. But, how would we see this utilized in a programming scenario?
To interact with the slice, we must first assign it to a variable:
mySlice2 := []interface{}{7, "Hello", false, 63.5};
fmt.Println(mySlice2);
# Output: [7, "Hello", false, 63.5]
... and now let's log the item at index 1 (the second item since the first item is always 0) using index notation:
let firstIndexMySlice = mySlice2[1]; console.log(firstIndexMySlice); # Output: "Hello"
Try logging the third index into the console using index notation. I've already defined the slice for you below. Click run when you're ready to run the code! The output should be 63.5.
mySlice3 := []interface{}{7, "Hello", false, 63.5};
thirdIndexMySlice := mySlice3[3];
fmt.Println(thirdIndexMySlice);
# Output: 63.5