I am having a hard time understanding some type assertions in Go and why below code will not work and result in a panic.
panic: interface conversion: interface {} is []db.job, not []main.job
Main:
/*stackTypeAssert.go
> panic: interface conversion: interface {} is []db.job, not []main.job
*/
package main
import (
"fmt"
"stackTypeAssert/db"
)
type job struct {
ID int
Status string
}
type jobs interface{}
func main() {
jobTable := db.GetJobs()
fmt.Println(jobTable) // This works: [{1 pending} {2 pending}]
//Type Assertion
var temp []job
//panic: interface conversion: interface {} is []db.job, not []main.job
temp = jobTable.([]job)
fmt.Println(temp)
}
Package db:
/*Package db ...
panic: interface conversion: interface {} is []db.job, not []main.job
*/
package db
//GetJobs ...
func GetJobs() interface{} {
//Job ...
type job struct {
ID int
Status string
}
task := &job{}
var jobTable []job
for i := 1; i < 3; i++ {
*task = job{i, "pending"}
jobTable = append(jobTable, *task)
}
return jobTable
}
In go lang spec for Import declarations it is described as:-
The PackageName is used in qualified identifiers to access exported identifiers of the package within the importing source file. It is declared in the file block. If the PackageName is omitted, it defaults to the identifier specified in the package clause of the imported package. If an explicit period (.) appears instead of a name, all the package's exported identifiers declared in that package's package block will be declared in the importing source file's file block and must be accessed without a qualifier.
As the error says:-
panic: interface conversion: interface {} is []db.job, not []main.job
You should use the struct of db
package by importing it inside main to create temp variable, since the returned value is an interface wrapping the struct db.jobs
not main.jobs
package main
import (
"fmt"
"stackTypeAssert/db"
)
type job struct {
ID int
Status string
}
type jobs interface{}
func main() {
jobTable := db.GetJobs()
fmt.Println(jobTable) // This works: [{1 pending} {2 pending}]
// create a temp variable of []db.Job type
var temp []db.Job
// get the value of interface returned from `GetJobs` function in db package and then use type assertion to get the underlying slice of `db.Job` struct.
temp = jobTable.(interface{}).([]db.Job)
fmt.Println(temp)
}
In db
package file define the struct outside GetJobs()
function and make it exportable by converting the struct to uppercase
.
package db
// make it exportable by converting the name of struct to uppercase
type Job struct {
ID int
Status string
}
//GetJobs ...
func GetJobs() interface{} {
task := &Job{}
var jobTable []Job
for i := 1; i < 3; i++ {
*task = Job{i, "pending"}
jobTable = append(jobTable, *task)
}
return jobTable
}
Output
[{1 pending} {2 pending}]
[{1 pending} {2 pending}]
For more information on exported identifier, you can check this link Exported functions from another package