0

I have defined and created an instance of a struct in my main.go file. And I want to call a function from the functions/functions.go file using an instance of my struct as the parameter

package main

import (
    "./functions"
)

type person struct {
    name string
    age  int
}

func main() {
    person1 := person{"James", 24}
    functions.Hello(person1)
}

main.go

package functions

import "fmt"

type person struct {
    name string
    age  int
}

func Hello(p person) {
    fmt.Println(p.name, "is", p.age, "years old")
}

functions/functions.go

When I run this code with: go run main.go, I get the error: main.go:16:17: cannot use person1 (type person) as type functions.person in argument to functions.Hello

My question

What is the correct way to pass an instance of a struct as parameter to an imported function in Go?

James Dean
  • 205
  • 4
  • 10
  • That is not how types work in Go. You must redesign. – Volker Sep 13 '20 at 19:11
  • @Volker could you elaborate/ be a bit more specific? – James Dean Sep 13 '20 at 19:26
  • There is a difference between "convertibility" and "assignability" of types. To be convertible two types must have the same underlying representation (your types do) but as they are from differente packages they are _different_ types and thus not assignable to each other without explicit conversion first. And one is unexported and thus "private" and unusable outside of the package. I'd recommend the Tour of GO and its exercises which explain such language fundamentals. – Volker Sep 14 '20 at 05:25

2 Answers2

2

The issue is that you have 2 separate person definition. Instead of redeclaring it in main, use the one in package function.

package functions

import "fmt"

type Person struct {
    Name string
    Age  int
}

func Hello(p Person) {
    fmt.Println(p.name, "is", p.age, "years old")
}

Changed to capital letter for Person and it's fields to make them export.

package main

import (
    "./functions"
)

func main() {
    person1 := functions.Person{"James", 24}
    functions.Hello(person1)
}
super
  • 12,335
  • 2
  • 19
  • 29
  • Thank you for your answer. This code runs correctly, but you need to edit it slightly. The fields where the Person struct is defined need to be capitalized since they are exported. So, `Name` not `name`, and `Age` not `age`. – James Dean Sep 13 '20 at 19:24
1

You're defining two different struct types (that have the same fields, but are different) - one of them is person and the other one is called functions.person.

The correct way, in this case, would be defining your struct in functions/functions.go like this:

package functions

import "fmt"

// Use uppercase names to export struct and fields (export == public)
type Person struct {
    Name string
    Age  int
}

func Hello(p Person) {
    fmt.Println(p.Name, "is", p.Age, "years old")
}

Now in main.go, you can import the package functions and access its exported/public structs:

package main

import (
    "./functions"
)

// No need to redeclare the struct, it's already defined in the imported package    

func main() {
    // create an object of struct Person from the functions package. Since its fields are public, we can set them here
    person1 := functions.Person{"James", 24}

    // call the Hello method from the functions package with an object of type functions.Person
    functions.Hello(person1)
}

The key takeaway is that structs defined with the same name are not automatically the same, even if they seem similar - they are defined differently after all.

You can also do type conversions if two structs have the same fields, but that's a different story.

xarantolus
  • 1,961
  • 1
  • 11
  • 19
  • Thank you for your detailed answer. Yes it makes sense to me now that though they may be similar, they are infact two distinct definitions. Exporting the struct from `function.go` is a good solution to this problem. – James Dean Sep 13 '20 at 19:34