Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
169 views
in Technique[技术] by (71.8m points)

json - Assign value to slice of struct which the slice have no length

I have a slice of struct to accommodate data from the database. My struct looks like this:

type TempGigs struct {
    Id           int     `json:"id" db:"id"`
    Title        string  `json:"title" db:"title"`
    UserID       int     `json:"user_id" db:"user_id"`
    Price        int     `json:"price" db:"price"`
    Currency     string  `json:"currency" db:"currency"`
    Username     string  `json:"username" db:"username"`
    ImageProfile string  `json:"image_profile" db:"image_profile"`
    Level        string  `json:"level" db:"level"`
    GigRating    float64 `json:"gig_rating" db:"gig_rating"`
    TotalReview  int     `json:"total_review" db:"total_review"`
    CreatedAt    int     `json:"created_at" db:"created_at"`
    Favorite     bool    `json:"favorite" db:"favorite"`
}

I want to move the data from a []TempGigs to a []Gigs. The Gigs struct is defined as:

type ResponseGigs struct {
    SectionName string `json:"section_name"`
    Offset      int    `json:"offset"`
    Limit       int    `json:"limit"`
    TotalRows   int    `json:"total_rows"`
    Gigs        []struct {
        SellerInfo struct {
            UserID       int    `json:"user_id"`
            Username     string `json:"username"`
            Name         string `json:"name"`
            ImageProfile string `json:"image_profile"`
            Level        string `json:"level"`
        } `json:"seller_info"`
        ID     int    `json:"id" db:"id"`
        Title  string `json:"title" db:"title"`
        Medias []struct {
            ID       int    `json:"id"`
            Name     string `json:"name"`
            TypeFile string `json:"type_file"`
            ImageURL string `json:"image_url"`
        } `json:"medias"`
        Price    int    `json:"price"`
        Currency string `json:"currency"`
        Rating   struct {
            AVGRating    float64 `json:"avg_rating"`
            TotalReviews int     `json:"total_reviews"`
        } `json:"rating"`
        Favorite bool `json:"favorite"`
    } `json:"gigs"`
}

When I iterate the TempGigs with for to copy to []Gigs, there is no error while compiling. But when a request is submitted the program panics with panic: runtime error: index out of range [0] with length 0. I have tried to use append but I don't understand how to use append correctly.

This is my iteration code:

tempGigs := []TempGigs{}
tempResp := ResponseGigs{}
tempResp.SectionName = "Best seller"
tempResp.Offset = 0
tempResp.Limit = 10
for i := range tempGigs {
    tempResp.Gigs[i].SellerInfo.UserID = tempGigs[i].UserID
    tempResp.Gigs[i].SellerInfo.Name = tempGigs[i].Username
    tempResp.Gigs[i].SellerInfo.ImageProfile = fmt.Sprintf("%s/%s", os.Getenv("STORAGE_URL"), tempGigs[i].ImageProfile)
    tempResp.Gigs[i].SellerInfo.Level = tempGigs[i].Level
    tempResp.Gigs[i].ID = tempGigs[i].Id
    tempResp.Gigs[i].Title = tempGigs[i].Title
    tempResp.Gigs[i].Price = tempGigs[i].Price
    tempResp.Gigs[i].Currency = tempGigs[i].Currency
    tempResp.Gigs[i].Rating.AVGRating = tempGigs[i].GigRating
    tempResp.Gigs[i].Rating.TotalReviews = tempGigs[i].TotalReview
    tempResp.Gigs[i].Favorite = tempGigs[i].Favorite
}
utils.HTTPJsonSuccess(w, http.StatusOK, tempGigs)
return
question from:https://stackoverflow.com/questions/65641744/assign-value-to-slice-of-struct-which-the-slice-have-no-length

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Your question was already answered correctly in the comments, but maybe it helps you to get some more feedback on your code.

Extract sub types from struct(s)

ResponseGigs is a large struct with multiple sub-structs which makes it hard to work with. Extracting the sub-structs as extra types makes things easier.

type ResponseGigs struct {
    SectionName string `json:"section_name"`
    Offset      int    `json:"offset"`
    Limit       int    `json:"limit"`
    TotalRows   int    `json:"total_rows"`
    Gigs        []Gig  `json:"gigs"`
}

type Gig struct {
    SellerInfo SellerInfo `json:"seller_info"`
    ID         int        `json:"id" db:"id"`
    Title      string     `json:"title" db:"title"`
    Medias     []Media    `json:"medias"`
    Price      int        `json:"price"`
    Currency   string     `json:"currency"`
    Rating     Rating     `json:"rating"`
    Favorite   bool       `json:"favorite"`
}

type SellerInfo struct {
    UserID       int    `json:"user_id"`
    Username     string `json:"username"`
    Name         string `json:"name"`
    ImageProfile string `json:"image_profile"`
    Level        string `json:"level"`
}

type Media struct {
    ID       int    `json:"id"`
    Name     string `json:"name"`
    TypeFile string `json:"type_file"`
    ImageURL string `json:"image_url"`
}

type Rating struct {
    AVGRating    float64 `json:"avg_rating"`
    TotalReviews int     `json:"total_reviews"`
}

type TempGig struct {
    Id           int     `json:"id" db:"id"`
    Title        string  `json:"title" db:"title"`
    UserID       int     `json:"user_id" db:"user_id"`
    Price        int     `json:"price" db:"price"`
    Currency     string  `json:"currency" db:"currency"`
    Username     string  `json:"username" db:"username"`
    ImageProfile string  `json:"image_profile" db:"image_profile"`
    Level        string  `json:"level" db:"level"`
    GigRating    float64 `json:"gig_rating" db:"gig_rating"`
    TotalReview  int     `json:"total_review" db:"total_review"`
    CreatedAt    int     `json:"created_at" db:"created_at"`
    Favorite     bool    `json:"favorite" db:"favorite"`
}

Create an extra function to transform TempGig to Gig

Next I'd do is create a function to convert a TempGig to a Gig. (I renamed TempGigs to TempGig as the struct only holds a single gig, not multiple):

func toGig(in TempGig) Gig {
    return Gig{
        SellerInfo: SellerInfo{
            UserID:       in.UserID,
            Name:         in.Username,
            ImageProfile: in.ImageProfile,
            Level:        in.Level,
        },
        ID:       in.Id,
        Title:    in.Title,
        // ...
    }
}

Fill the response slice

To keep the handler code minimal, I'd also create an extra function for building the ResponseGigs struct. For exammple:

func toResponse(section string, in []TempGig) ResponseGigs {
    var gigs []Gig
    // or to preallocate the memory space / capacity (not the length!)
    // gigs := make([]Gig, 0, len(in))

    for _, tempGig := range in {
        gigs = append(gigs, toGig(tempGig))
    }
    
    return ResponseGigs{
        SectionName: section,
        Gigs:        gigs,
    }
}

Alternatively you can preallocate the length of the slice and work with indexes. I prefer the append approach as it is less error prone.

    // preallocate the length of the slice (not only the capacity)
    gigs := make([]Gig, len(in))
    for i, tempGig := range in {
        gigs[i] = toGig(tempGig)
    }

Handler code

Finally the handler code would boil down to something like this:

    tempResp := toReponse("Best seller", tempGigs)
    tempResp.Offset = 0
    tempResp.Limit = 10
    utils.HTTPJsonSuccess(w, http.StatusOK, tempResp)
    return

Hope this helps as a next step. There are many things that can be adjusted to your liking. Happy Coding!


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...