How to pass struct as a function argument in Go? - go

package main
import "fmt"
type Person struct {
name string
age int
job string
salary int
}
func test(class Person) {
// Access and print Pers1 info
fmt.Println("Name: ", class.name)
fmt.Println("Age: ", class.age)
fmt.Println("Job: ", class.job)
fmt.Println("Salary: ", class.salary)
}
func main() {
var pers1 Person
var pers2 Person
// Pers1 specification
pers1.name = "Hege"
pers1.age = 45
pers1.job = "Teacher"
pers1.salary = 6000
// Pers2 specification
pers2.name = "Cecilie"
pers2.age = 24
pers2.job = "Marketing"
pers2.salary = 4500
}
/* This is my code. I want to pass whole struct to a function test as argument. But i don't know the syntax of like how can i achieve this. Kindly look into this and help me*/

You should pass it to function calling as test(pers1) and test(pers2)

package main
import "fmt"
type Person struct {
name string
age int
job string
salary int
}
func test(class Person) {
// Access and print Pers1 info
fmt.Println("Name: ", class.name)
fmt.Println("Age: ", class.age)
fmt.Println("Job: ", class.job)
fmt.Println("Salary: ", class.salary)
}
func main() {
var pers1 Person
var pers2 Person
// Pers1 specification
pers1.name = "Hege"
pers1.age = 45
pers1.job = "Teacher"
pers1.salary = 6000
// Pers2 specification
test(pers1)
pers2.name = "Cecilie"
pers2.age = 24
pers2.job = "Marketing"
pers2.salary = 4500
test(pers2)
}
/* Try this you have to pass it as test(pers1) and test(pers2). I hope it works fine now.*/

Related

Convert string in struct to []string

I have a struct as below:
type TourData struct {
ArtistID int //artist ID
RelationID string //key for relations
City string
Country string
TourDates []string
}
type MyRelation struct {
ID int `json:"id"`
DatesLocations map[string][]string `json:"datesLocations"`
}
which contains this data from a csv file:
1,nagoya-japan,Nagoya,Japan,
1,penrose-new_zealand,Penrose,New_Zealand,
1,dunedin-new_zealand,Dunedin,New_Zealand,
2,playa_del_carmen-mexico,Playa Del Carmen,Mexico,
2,papeete-french_polynesia,Papeete,French_Polynesia,
MyRelations is populated from an API which contains:
"index": [
{
"id": 1,
"datesLocations": {
"dunedin-new_zealand": [
"10-02-2020"
],
"nagoya-japan": [
"30-01-2019"
],
"penrose-new_zealand": [
"07-02-2020"
]
}
},
{
"id": 2,
"datesLocations": {
"papeete-french_polynesia": [
"16-11-2019"
],
"playa_del_carmen-mexico": [
"05-12-2019",
"06-12-2019",
"07-12-2019",
"08-12-2019",
"09-12-2019"
]
}
}
The dates come from another struct. The code I have used to populate this struct is as below:
var oneRecord TourData
var allRecords []TourData
for _, each := range csvData {
oneRecord.ArtistID, _ = strconv.Atoi(each[0])
oneRecord.RelationID = each[1]
oneRecord.City = each[2]
oneRecord.Country = each[3]
oneRecord.TourDates = Relations.Index[oneRecord.ArtistID-1].DatesLocations[each[1]]
allRecords = append(allRecords, oneRecord)
}
jsondata, err := json.Marshal(allRecords) // convert to JSON
json.Unmarshal(jsondata, &TourThings)
I need to group all the 1s together then the 2s etc. I thought to create another struct, and populate from this one but not having much luck - any ideas?
To clarify I would want say TourData.City to equal:
[Nagoya,Penrose,Dunedin]
[Playa Del Carmen, Papeete]
At the moment if I was to print TourData[0].City I would get Nagoya.
I have tried creating another struct to be populated from the TourData struct with the following fields:
type TourDataArrays struct {
ArtistID int
City []string
Country []string
TourDates [][]string
}
and then populate the struct using the code below:
var tourRecord TourDataArrays
var tourRecords []TourDataArrays
for i := 0; i < len(Relations.Index); i++ {
for j := 0; j < len(allRecords); j++ {
if allRecords[i].ArtistID == i+1 {
tourRecord.City = append(tourRecord.City, allRecords[j].City)
}
}
tourRecords = append(tourRecords, tourRecord)
}
However this is adding all the cities to one array i.e
[Nagoya, Penrose, Dunedin, Playa Del Carmen, Papeete].
If I understand your requirements correctly you needed to declare city as a string array as well. (And Country to go with it).
Check out this solution : https://go.dev/play/p/osgkbfWV3c5
Note I have not deduped country and derived city and country from one field in the Json.

Go and Fyne - Need response from dialog and enable/disable Submit button

Just starting to look at both Go and Fyne. After writing a test CRUD program using information obtained from examples, I need to solve the following:
I need an initial Dialog or similar in order to allow selection of an existing record or "new" to indicate a new record. My existing Dialog does not handle this adequately.
I need to be able to enable/disable the Submit button to allow or disallow update if the data has has-not changed.
The program compiles without error, however "go vet" and VsCode indicates (eg. for line):
{"Given Names:", arwWidgets[I_NDX_GIVEN]},
go vet shows:
ERROR: "unknown field 'Key' in struct literal of type widget.FormItem",
however, if I include a key, compiler fails.
Being new to both Go and Fyne, there are probably fundamental mistakes.
Test program is as follows:
package main
// Dependency: local directory "data".
import (
"errors"
"io/ioutil"
"log"
"os"
"strings"
"fyne.io/fyne"
"fyne.io/fyne/app"
"fyne.io/fyne/dialog"
"fyne.io/fyne/layout"
"fyne.io/fyne/widget"
)
const BY_SEP byte = byte('|')
const I_ARRAY_LEN int = 10
const I_NDX_GIVEN int = 0
const I_NDX_FAMILY int = 1
const I_NDX_TITLE int = 2
const I_NDX_ADDR1 int = 3
const I_NDX_ADDR2 int = 4
const I_NDX_ADDR3 int = 5
const I_NDX_STATE int = 6
const I_NDX_ZIP int = 7
const I_NDX_TELE1 int = 8
const I_NDX_TELE2 int = 9
var _arsOldData [I_ARRAY_LEN]string
var _arsNewData [I_ARRAY_LEN]string
var _tfDataHasChanged bool
var _sKey string
var _arwEntryWidgets [I_ARRAY_LEN]*widget.Entry
var _wApp fyne.App
var _wWindow fyne.Window
var _wModal widget.PopUp
var _wFormKeyEntry widget.Form
//-------------------------------------------------------------------------------
func main() {
log.Println("In fytest01")
_, err := os.Stat("./data/")
if err != nil {
log.Println("You need to create directory: 'data'")
os.Exit(1)
}
//fnReadData()
_wApp := app.New()
_wWindow := _wApp.NewWindow("Customer Details")
//_wFormKeyEntry := fnCreateKeyForm()
wFormMain := fnCreateMainForm()
//_wModal := widget.NewModalPopUp(_wFormKeyEntry, _wWindow.Canvas())
_wWindow.Resize(fyne.NewSize(500, 400))
_wWindow.CenterOnScreen()
_wWindow.SetContent(widget.NewVBox(
wFormMain,
widget.NewGroup("",
fyne.NewContainerWithLayout(layout.NewGridLayout(2),
widget.NewButton("Exit", func() {
_wApp.Quit()
}),
widget.NewButton("Submit", func() {
log.Println("Submit button pressed")
err := fnUpdateData()
if err == nil {
dialog.ShowInformation("Information", "Data was updated", _wWindow)
wEntryForKey := widget.NewEntry()
wEntryForKey.SetPlaceHolder("Enter Key (4) : ")
wEntryForKey.OnChanged = func(sKey string) {
log.Println("Entered", sKey)
if len(sKey) == 4 {
_sKey = sKey
}
if len(_sKey) == 4 {
dialog.ShowInformation("Information", "Key "+_sKey+" has been entered - press OK", _wWindow)
fnReadData()
fnRefreshWidgetData()
}
}
dialog.ShowCustom("Enter Customer Key", "OK", wEntryForKey, _wWindow)
} else {
dialog.ShowError(err, _wWindow)
}
}),
))),
)
//fnShowKeyEntryDialog()
wEntryForKey := widget.NewEntry()
wEntryForKey.SetPlaceHolder("Enter Key (4) : ")
wEntryForKey.OnChanged = func(sKey string) {
log.Println("Entered", sKey)
if len(sKey) == 4 {
_sKey = sKey
}
if len(_sKey) == 4 {
dialog.ShowInformation("Information", "Key "+_sKey+" has been entered - press OK", _wWindow)
fnReadData()
fnRefreshWidgetData()
}
}
dialog.ShowCustom("Enter Customer Key", "OK", wEntryForKey, _wWindow)
_wWindow.ShowAndRun()
//_wModal.Show()
}
//-------------------------------------------------------------------------------
func fnCreateAllEntryWidgets() {
_arwEntryWidgets[I_NDX_GIVEN] = fnCreateSingleEntryWidget(I_NDX_GIVEN)
_arwEntryWidgets[I_NDX_FAMILY] = fnCreateSingleEntryWidget(I_NDX_FAMILY)
_arwEntryWidgets[I_NDX_TITLE] = fnCreateSingleEntryWidget(I_NDX_TITLE)
_arwEntryWidgets[I_NDX_ADDR1] = fnCreateSingleEntryWidget(I_NDX_ADDR1)
_arwEntryWidgets[I_NDX_ADDR2] = fnCreateSingleEntryWidget(I_NDX_ADDR2)
_arwEntryWidgets[I_NDX_ADDR3] = fnCreateSingleEntryWidget(I_NDX_ADDR3)
_arwEntryWidgets[I_NDX_STATE] = fnCreateSingleEntryWidget(I_NDX_STATE)
_arwEntryWidgets[I_NDX_ZIP] = fnCreateSingleEntryWidget(I_NDX_ZIP)
_arwEntryWidgets[I_NDX_TELE1] = fnCreateSingleEntryWidget(I_NDX_TELE1)
_arwEntryWidgets[I_NDX_TELE2] = fnCreateSingleEntryWidget(I_NDX_TELE2)
}
//-------------------------------------------------------------------------------
func fnCreateSingleEntryWidget(iNdxData int) *widget.Entry {
wEntry := widget.NewEntry()
wEntry.SetText(_arsOldData[iNdxData])
wEntry.OnChanged = func(sText string) {
_arsNewData[iNdxData] = sText
fnCheckIfDataHasChanged()
}
return wEntry
}
//-------------------------------------------------------------------------------
func fnCreateFormFields(arwWidgets [I_ARRAY_LEN]*widget.Entry) []*widget.FormItem {
return []*widget.FormItem{
{"Given Names:", arwWidgets[I_NDX_GIVEN]},
{"Family Name: ", arwWidgets[I_NDX_FAMILY]},
{"Title: ", arwWidgets[I_NDX_TITLE]},
{"Address Ln 1: ", arwWidgets[I_NDX_ADDR1]},
{" '' Ln 2: ", arwWidgets[I_NDX_ADDR2]},
{" '' Ln 3: ", arwWidgets[I_NDX_ADDR3]},
{" '' State ", arwWidgets[I_NDX_STATE]},
{" '' Zip: ", arwWidgets[I_NDX_ZIP]},
{"Telephone 1: ", arwWidgets[I_NDX_TELE1]},
{"Telephone 2: ", arwWidgets[I_NDX_TELE2]},
}
}
//-------------------------------------------------------------------------------
func fnCheckIfDataHasChanged() {
var tfChanged bool = false
for iNdxData := 0; !tfChanged && iNdxData < len(_arsOldData); iNdxData++ {
tfChanged = (_arsNewData[iNdxData] != _arsOldData[iNdxData])
}
if tfChanged != _tfDataHasChanged {
_tfDataHasChanged = tfChanged
if tfChanged {
// COULD NOT CREATE _wBtnSubmitMain AS A GLOBAL VARIABLE.
//_wBtnSubmitMain.Show()
//_wBtnSubmitMain.Enable()
} else {
//_wBtnSubmitMain.Disable()
//_wBtnSubmitMain.Hide()
}
}
}
//-------------------------------------------------------------------------------
func fnReadData() {
_tfDataHasChanged = false
log.Println("fnReadData: Key = " + _sKey)
var sData string
if len(_sKey) > 0 {
arbData, _ := ioutil.ReadFile("./data/" + _sKey)
if arbData != nil {
sData = string(arbData)
}
}
log.Println("fnReadData: sData = " + sData)
/* CLEAR OLD DATA */
for iNdxData := 0; iNdxData < I_ARRAY_LEN; iNdxData++ {
_arsOldData[iNdxData] = ""
}
/* POPULATE DATA IF ANY */
var iNdx1 int = 0
var iNdxData int = 0
var iLen int = len(sData)
for iNdx2 := 0; iNdx2 < len(sData); iNdx2++ {
if sData[iNdx2] == BY_SEP {
_arsOldData[iNdxData] = sData[iNdx1:iNdx2]
iNdx1 = iNdx2 + 1
iNdxData++
} else if iNdx2 == (iLen - 1) {
_arsOldData[iNdxData] = sData[iNdx1 : iNdx2+1]
}
}
for iNdx := 0; iNdx < I_ARRAY_LEN; iNdx++ {
_arsNewData[iNdx] = _arsOldData[iNdx]
}
}
//-------------------------------------------------------------------------------
func fnUpdateData() error {
if !_tfDataHasChanged {
return errors.New("Data has not changed")
}
if len(_sKey) < 1 {
_sKey = "9999"
//dialog.ShowInformation("Information", "Default key of 9999 was used", _wWindow) // CAUSES ERROR
}
var sNewData string = ""
for iNdxData, sVal := range _arsNewData {
if strings.Index(sVal, "|") >= 0 {
sVal = strings.ReplaceAll(sVal, "|", ":")
}
if iNdxData != I_ARRAY_LEN-1 {
sNewData += sVal + string(BY_SEP)
} else {
sNewData += sVal
}
}
log.Println("New Data = " + sNewData)
var err error = ioutil.WriteFile("./data/"+_sKey, []byte(sNewData), 0644)
if err == nil {
for iNdxData := 0; iNdxData < len(_arsNewData); iNdxData++ {
_arsOldData[iNdxData] = _arsNewData[iNdxData]
}
fnCheckIfDataHasChanged()
}
return err
}
//-------------------------------------------------------------------------------
func fnCreateKeyForm() *widget.Form {
wEntryKey := widget.NewEntry()
return &widget.Form{
Items: []*widget.FormItem{
{"Key:", wEntryKey}},
OnSubmit: func() {
_sKey = wEntryKey.Text
log.Println("Key = " + _sKey)
fnReadData()
log.Println("Data has been read")
fnRefreshWidgetData()
_wFormKeyEntry.Hide()
//_wModal.Hide()
},
}
}
//-------------------------------------------------------------------------------
//func fnCreateMainWindow() {
// log.Println("Creating Main Window Form")
// wFormMain := fnCreateMainForm()
// log.Println("Creating Main Window Window")
// _wWindow.SetContent( //widget.NewVBox(
// wFormMain,
// )
//}
//-------------------------------------------------------------------------------
func fnCreateMainForm() *widget.Form {
log.Println("Create form1 widgets")
fnCreateAllEntryWidgets()
log.Println("Create form1 FormFields")
arwFormFields := fnCreateFormFields(_arwEntryWidgets)
log.Println("Creating Form1")
return &widget.Form{
Items: arwFormFields,
}
}
//-------------------------------------------------------------------------------
func fnRefreshWidgetData() {
for iNdx := 0; iNdx < I_ARRAY_LEN; iNdx++ {
_arwEntryWidgets[iNdx].SetText(_arsNewData[iNdx])
}
}
Can you just add a "New" button to the start window which fills in defaults then opens the main window. Does that make sense?
You create the Submit button by creating and passing it directly to SetContent. You need to save it in a variable, so that you can at some point call Disable() on it.
submitButton := widget.NewButton("Submit", func() {
log.Println("Submit button pressed")
...
})
_wWindow.SetContent(widget.NewVBox(
wFormMain,
widget.NewGroup("",
fyne.NewContainerWithLayout(layout.NewGridLayout(2),
widget.NewButton("Exit", func() {
_wApp.Quit()
}),
submitButton,
))),
)
...
if dataChanged {
submitButton.Enable()
} else {
submitButton.Disable()
}
I think the go vet message is saying you should name all the fields in your struct literal (though I get a different message to you using Go 1.13). Go allows you to add the values by order or by name - go vet is telling you that by name is safer (eg if fields are moved or inserted to the FormItem struct then your code would be broken).
Ie:
return []*widget.FormItem{
{ Text: "Given Names:", Widget: arwWidgets[I_NDX_GIVEN]},
...
Also it may simplify things to put all your global variables into a struct and then you can have "methods" on the struct. (There are a few reasons to avoid globals which you probably already know. I appreciate that this probably started as a simple test that has grown but it may be a good time to refactor.)
To change button options on toggle you need to use something like this:
buttonTitle := "Disable"
button := widget.NewButton(buttonTitle, nil)
changeButton := func() {
// here could be your logic
// how to disable/enable button
if button.Text == "Disable" {
buttonTitle = "Enable"
//button.Disable()
}
button.SetText(buttonTitle)
button.Refresh()
}
button.OnTapped = changeButton

Insert call a method and insert values

I have this working in another programming language, creating a url to reverse geocode a location. I am new to Go and I am slowly working building up the script.
I have the method Geofunction(x,y) with the two variables x & y
From another method I call the above method and supply the values to the variables.
I just can't get it to work as expected.
Could someone point me to where to help me find the answer give me some help on this please.
I have a working coy in Python, as I learn Go I am translating scripts understand.
I have made changes to allow certain variable to accessible to the other functions. I need to understand if the method called with be able to access the variable values.
package main
import "fmt"
var Location1x, Location1y string
var Location1 string
var rev_geo string
func Geofunction(x, y) {
var str1 string = "https://eu1.locationiq.com/v1/reverse.php?key="
var str2 string = "**********************" //API Key
var str3 string = x // '48.853106'
var str4 string = "&lon="
var str5 string = y // '2.384202'
var str6 string = "&format=json"
var rev_geo string = str1 + str2 + str3 + str4 + str5 + str6
return rev_geo
}
func Locator() {
Location1x, Location1y = "48.853106", "2.384202"
Location1 = Geofunction(Location1x, Location1y)
}
func main() {
Locator()
fmt.Println(Location1)
}```
Expected:
A string of a URL is printed.
The three errors are:
main.go:9:18: undefined: x
main.go:9:21: undefined: y
Geofunction(Location1x, Location1y) used as value
Once I get the above sorted, I will then reuse the method to produce multiple strings in an API test that confirms specific data in the json files returned from the server
You are missing a few pieces.
The types for x and y in the function definition are missing. Since the are both strings, the type can be defined simultaneously.
The function GeoFunction is missing a return type, which should be string
Go is quite strict about syntax and structure, unlike Python - I would strongly suggest completing the the Go Tour before transpiling any code, it will make things a lot smoother for you.
Try something like:
package main
import (
"fmt"
)
var Location1x, Location1y string
var Location1 string
var rev_geo string
func Geofunction(x, y string) string {
var str1 string = "https://eu1.locationiq.com/v1/reverse.php?key="
var str2 string = "**********************" //API Key
var str3 string = x // '48.853106'
var str4 string = "&lon="
var str5 string = y // '2.384202'
var str6 string = "&format=json"
var rev_geo string = str1 + str2 + str3 + str4 + str5 + str6
return rev_geo
}
func Locator() {
Location1x, Location1y = "48.853106", "2.384202"
Location1 = Geofunction(Location1x, Location1y)
}
func main() {
Locator()
fmt.Println(Location1)
}
Your method definition is wrong overe here, given go is a statically typed language your function definitions should have the type of the parameters which it takes alongside the parameter names
package main
import "fmt"
var Location1x, Location1y string
var Location1 string
var rev_geo string
func Geofunction(x string, y string) {
var str1 string = "https://eu1.locationiq.com/v1/reverse.php?key="
var str2 string = "**********************" //API Key
var str3 string = x // '48.853106'
var str4 string = "&lon="
var str5 string = y // '2.384202'
var str6 string = "&format=json"
var rev_geo string = str1 + str2 + str3 + str4 + str5 + str6
return rev_geo
}
func Locator() {
Location1x, Location1y = "48.853106", "2.384202"
Location1 = Geofunction(Location1x, Location1y)
}
func main() {
Locator()
fmt.Println(Location1)
}
This should basically work, but a better approach to this would be to use a string builder instead of appending strings. That’s more efficient

Why the warning: "Constant <name> inferred to have type (), which may be unexpected"?

I'm attempting to sort an array of instantiated items of the class: "Employees".
However I'm getting the following error within my playground:
Here's the code as written in my playground:
class Employee {
var firstName:String = ""
var lastName:String = ""
init(fName:String, lName:String) {
self.firstName = fName
self.lastName = lName
}
}
var employees = [Employee]()
// 1)
var employee = Employee(fName: "Ric", lName: "Lee")
employees.append(employee)
// 2)
employee = Employee(fName: "Ralph", lName: "Knott")
employees.append(employee)
// 3)
employee = Employee(fName: "Joe", lName: "Smirf")
employees.append(employee)
// 4)
employee = Employee(fName: "Meredith", lName: "Lind")
employees.append(employee)
// 5)
employee = Employee(fName: "Aarnald", lName: "Zingerhost")
employees.append(employee)
let sortedEmployees = employees.sort { (e1:Employee, e2:Employee) -> Bool in
e1.lastName < e2.lastName
}
What am I missing here?
Why the warning?
The reason is that you are using the wrong function (former sortInPlace):
In Swift 3
sort() has been renamed to sorted()
sortInPlace() has been renamed to sort()
Therefore it's
let sortedEmployees = employees.sorted { (e1:Employee, e2:Employee) -> Bool in
e1.lastName < e2.lastName
}
Source: Swift Evolution: Apply API Guidelines to the Standard Library
try declaring
let sortedEmployees = employees.sort { (e1:Employee, e2:Employee) -> Bool in
e1.lastName < e2.lastName}
as
let sortedEmployees : () = employees.sort { (e1:Employee, e2:Employee) -> Bool in
e1.lastName < e2.lastName}

Instance member cannot be use on type

#IBAction func saveDetails(sender: AnyObject) {
Person.firstName = firstNameTF.text
Person.lastName = lastNameTF.text
}
Above is the function I am trying to implement and below is the class I am trying to create an instance of and store the data from my text fields in... I am getting the error "Instance member "firstName" cannot be used on type Person". I was almost positive that my class was setup and initialised properly so I can't see what the problem could be?
class Person {
var firstName : String = ""
var middleName : String? = nil
var lastName : String = ""
var yearOfBirth : Int? = nil
var age : Int! {
get {
guard let _ = yearOfBirth else {
return nil
}
return currentYear - yearOfBirth!
}
set {
yearOfBirth = currentYear - newValue
}
}
init(firstName: String, lastName: String, yearOfBirth: Int? = nil, middleName: String? = nil){
self.firstName = firstName
self.lastName = lastName
self.yearOfBirth = yearOfBirth
self.middleName = middleName
}
convenience init(firstName: String, lastName: String, age: Int, middleName: String? = nil) {
self.init(firstName: firstName, lastName: lastName, yearOfBirth: nil, middleName: middleName)
self.age = age
}
}
The error message says you cannot call the properties on the class (type) Person.
Create a Person instance using the given initializer
#IBAction func saveDetails(sender: AnyObject) {
let person = Person(firstName:firstNameTF.text, lastName:lastNameTF.text)
// do something with person
}
You should create an instance of Person in order to set its properties:
either do this:
#IBAction func saveDetails(sender: AnyObject) {
let p = Person(firstName: firstNameTF.text!, lastName: lastNameTF.text!)
}
or add an init method that doesn't take arguments to your Person class
#IBAction func saveDetails(sender: AnyObject) {
let p = Person()
p.firstName = firstNameTF.text!
p.lastName = lastNameTF.text!
}
"Instance member "firstName" cannot be used on type Person" is perfect explanation.
class C {
var s: String = ""
static var s1: String = ""
}
C.s1 = "alfa"
//C.s = "alfa" // error: instance member 's' cannot be used on type 'C'
let c0 = C()
c0.s = "beta"
//c0.s1 = "beta" // error: static member 's1' cannot be used on instance of type 'C'

Resources