Введите Assertion, используя идентичные структуры между пакетами - PullRequest
0 голосов
/ 06 июля 2018

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

паника: преобразование интерфейса: интерфейс {} - это [] db.job, а не [] 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 ...
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
}

1 Ответ

0 голосов
/ 06 июля 2018

В спецификации go lang для Декларации импорта это описывается как: -

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

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

паника: преобразование интерфейса: интерфейс {} - это [] 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}]

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

...