Утверждение типа с использованием идентичных структур между пакетами

Мне трудно понять некоторые утверждения типов в Go и почему приведенный ниже код не будет работать и приведет к панике.

паника: преобразование интерфейса: интерфейс {} — это []db.job, а не []main.job

Главный:

/*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 ...
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
}

person scruffy    schedule 06.07.2018    source источник


Ответы (1)


В спецификации go lang для объявлений импорта это описано как:

PackageName используется в квалифицированных идентификаторах для доступа к экспортированным идентификаторам пакета в исходном файле импорта. Он объявлен в блоке файла. Если PackageName опущен, по умолчанию используется идентификатор, указанный в предложении package импортируемого пакета. Если вместо имени появляется явная точка (.), все экспортируемые идентификаторы пакета, объявленные в блоке пакета этого пакета, будут объявлены в блоке файла исходного файла импорта, и доступ к ним должен осуществляться без квалификатора.

Как говорит ошибка: -

паника: преобразование интерфейса: интерфейс {} — это []db.job, а не []main.job

Вы должны использовать структуру пакета db, импортировав ее внутри main для создания временной переменной, поскольку возвращаемое значение представляет собой интерфейс, обертывающий структуру db.jobs, а не 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)
}

В файле пакета db определите структуру вне функции GetJobs() и сделайте ее экспортируемой, преобразовав структуру в 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
}

Вывод

[{1 pending} {2 pending}]
[{1 pending} {2 pending}]

Для получения дополнительной информации об экспортированном идентификаторе вы можете проверить эту ссылку Экспортированные функции из другого пакета

person Himanshu    schedule 06.07.2018