在结构体数组中更改对象值的最佳实践方法是什么?

huangapple go评论69阅读模式
英文:

Best practise for changing an objects value inside struct array

问题

我不知道这是否对学习一门语言的阶段有必要,但请告诉我关于这个主题的信息。

我有一个结构体数组 var movies []Movie,我正在使用Go语言构建一个CRUD API项目。

当我开始编写 updateHandler 处理 /movies/{id} 端点的 PUT 请求时,我不禁思考更新 movies 数组中对象的其他方法。

原始的方法(在教程视频中)是:

// 遍历电影,使用 range
// 删除具有传入参数中的 id 的电影
// 添加一个新的电影 - 请求体中发送的电影

for index, item := range movies {
    if item.ID == params["id"] {
        movies = append(movies[:index], movies[index+1:]...)

        var updatedMovie Movie
        json.NewDecoder(r.Body).Decode(&updatedMovie)

        updatedMovie.ID = params["id"]
        movies = append(movies, updatedMovie)
        json.NewEncoder(w).Encode(updatedMovie)
    }
}

但在观看教程之前,我尝试编写了自己的方法,如下所示:

for index, item := range movies {
    if item.ID == params["id"] {
        oldMovie := &movies[index]

        var updatedMovie Movie
        json.NewDecoder(r.Body).Decode(&updatedMovie)

        oldMovie.Isbn = updatedMovie.Isbn
        oldMovie.Title = updatedMovie.Title
        oldMovie.Director = updatedMovie.Director

        json.NewEncoder(w).Encode(oldMovie) // 返回 oldMovie,因为它带有 id
    }
}

如你所见,我将数组索引的指针赋值给了一个名为 oldMovie 的变量。

我还考虑了另一种方法,但效果不太好:

var updatedMovie Movie
json.NewDecoder(r.Body).Decode(&updatedMovie)

// 这个 linq 包是来自 github.com/ahmetalpbalkan/go-linq

oldMovie := linq.From(movies).FirstWithT(func(x Movie) bool {
    return x.ID == params["id"]
}).(Movie) 

// 但在这里我们只是赋值了值,而不是引用(或地址或指针)
// 所以每当我尝试获取所有电影时,它仍然返回
// 旧的电影列表而不是更新后的列表

oldMovie.Isbn = updatedMovie.Isbn
oldMovie.Title = updatedMovie.Title
oldMovie.Director = updatedMovie.Director

json.NewEncoder(w).Encode(oldMovie)

在我脑海中有一个想法,是否有可能像最后一种方法那样做(我无法在 linq 的开头放置 & 符号)?即使有一种方法,最佳实践是什么?

我应该像第一种方法那样(删除要更改的结构体并插入更新后的结构体),或者可能是第二种方法(分配数组中结构体的地址并进行更改),或者第三种方法与第二种方法相同(至少在我的想法中),只是使用我喜欢阅读和编写的 linq 包?

英文:

I dont't know if this is necessary for learning phase of a language but please enlighten me about this subject.

I have an array of struct as var movies []Movie and i am building a CRUD API project with golang.

When i start to write updateHandler which handling PUT requests to /movies/{id} endpoint, I couldn't help myself to think other ways of updating an object inside movies array.

The original way (in the tutorial video) was :

// loop over the movies, range
// delete the movie with the id that comes inside param
// add a new movie - the movie that we send in the body of request

for index, item := range movies {
	if item.ID == params["id"] {
		movies = append(movies[:index], movies[index+1:]...)

		var updatedMovie Movie
		json.NewDecoder(r.Body).Decode(&updatedMovie)

		updatedMovie.ID = params["id"]
		movies = append(movies, updatedMovie)
		json.NewEncoder(w).Encode(updatedMovie)
	}
}

but before i watch i tried to write my own method which is below :

for index, item := range movies {
	if item.ID == params["id"] {
		oldMovie := &movies[index]

		var updatedMovie Movie
		json.NewDecoder(r.Body).Decode(&updatedMovie)

		oldMovie.Isbn = updatedMovie.Isbn
		oldMovie.Title = updatedMovie.Title
		oldMovie.Director = updatedMovie.Director

		json.NewEncoder(w).Encode(oldMovie) // sending back oldMovie because it has the id with it
	}
}

As you can see i assigned the pointer of array's index to a variable which named as oldMovie.

I also think about another way too but it didn't go quite well

var updatedMovie Movie
json.NewDecoder(r.Body).Decode(&updatedMovie)

// this linq package is github.com/ahmetalpbalkan/go-linq from here

oldMovie := linq.From(movies).FirstWithT(func(x Movie) bool {
	return x.ID == params["id"]
}).(Movie) 

// But here we'r only assigning the value not the reference(or address or pointer) 
// so whenever i try to get all movies it still returning 
// the old movie list not the updated one

oldMovie.Isbn = updatedMovie.Isbn
oldMovie.Title = updatedMovie.Title
oldMovie.Director = updatedMovie.Director

json.NewEncoder(w).Encode(oldMovie)

Here I have something going around my head is there a possible way to do it like the last way (I couldnt put & to the beginning of linq) even if there is a way what would be the best practice ?

Should I do it like the first way (delete the struct which we want to change and insert the updated one) or maybe the second way (assign the address of struct inside array and change it) or the third way which same as the second (at least in my thoughts) but just using linq package which is i love to read and write ?

答案1

得分: 1

你包含的第一个案例是从切片中删除选定的项,然后附加新项。这需要进行可能很大的memmove操作,看起来没有实际目的。

你提供的第二个案例是可行的,但如果意图是替换对象的内容,有一种更简单的方法:

for index, item := range movies {
    if item.ID == params["id"] {
        json.NewDecoder(r.Body).Decode(&movies[index])
        // 这将发送更新后的电影
        json.NewEncoder(w).Encode(&movies[index]) 
        // 这将发送旧电影
        json.NewEncoder(w).Encode(item)
        break // 在这里停止搜索
    }
}

第三个代码片段没有返回指针,因此无法修改切片。

英文:

The first case you included removes the selected item from a slice, and then appends the new one. This requires a potentially large memmove with seemingly no real purpose.

The second case you have works, but there is a far easier way to do it if the intent is to replace the contents of the object:

for index, item := range movies {
    if item.ID == params["id"] {
        json.NewDecoder(r.Body).Decode(&movies[index])
        // This will send back the updated movie
        json.NewEncoder(w).Encode(&movies[index]) 
        // This will send back the old movie
        json.NewEncoder(w).Encode(item)
        break // Break here to stop searching
    }
}

The third snippet does not return a pointer, so you cannot modify the slice.

huangapple
  • 本文由 发表于 2022年9月13日 04:24:59
  • 转载请务必保留本文链接:https://go.coder-hub.com/73694906.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定