# #go #pointers #interface
Вопрос:
У меня есть сценарий, в котором я должен написать метод, в котором я изменяю базовую структуру переданного интерфейса, я понял, что могу передать указатель на интерфейс, а затем использовать указатель, чтобы получить базовую структуру и манипулировать ею, но из того, что я узнал, использование указателей на интерфейс почти никогда не требуется. Может ли кто-нибудь предложить какой-либо лучший способ достижения требуемой функциональности ниже?
package main
import (
"fmt"
)
type person struct {
name string
age int
}
type iperson interface {
walk()
changeName(string) *person
}
func (p person) walk() {
fmt.Println("tip tap toe")
}
func (p person) changeName(name string) *person {
return amp;person{name: name, age: p.age}
}
func modifyStr(s *string) {
*s = "world"
}
func modifyStruct(p *person) {
*p = person{name: "john", age: 10}
}
func modifyInterface(i iperson) {
//i.walk()
p := i.(*person)
*p = person{name: "diff name", age: 111}
}
func modifyInterfaceWithUnexportedStruct(target interface{}) {
// We can do so by type assertion on pointer to interface but this is not recommended
// this works but is there any other way possible? i.e without having access to underlying struct but still manipulating it?
p := target.(*iperson)
*p = *(*p).changeName("some random name")
}
func main() {
//modifying a string in a function call
a := "hello"
modifyStr(amp;a)
fmt.Println(a)
//modify a struct in a function call
b := person{name: "sam", age: 2}
modifyStruct(amp;b)
fmt.Println(b)
//modify a interface in a function call using the underlying struct
c := person{name: "tom", age: 2}
modifyInterface(amp;c)
fmt.Println(c)
//modify a passed interface in a function call without using the underlying struct
d := iperson(person{name: "abc", age: 21})
fmt.Println(d)
modifyInterfaceWithUnexportedStruct(amp;d)
fmt.Println(d)
}
Комментарии:
1. Что вы подразумеваете под личным? Вы имеете в виду неучтенный? Если это так, то вы НЕ можете изменять такую структуру вне пакета, в котором она объявлена. Если вы хотите изменить его только в рамках его собственного пакета, то то, что вы подразумеваете под «частным» и как это связано с вашим вопросом, становится еще менее ясным.
2. Этот вопрос не помешало бы прояснить… Независимо от того, экспортирована она или нет, вы не можете изменять структуру вне пакета, в котором она определена. Указатель на интерфейс почти никогда не бывает правильным или необходимым. Вы не можете манипулировать базовой структурой без утверждения типа, и если вы считаете, что вам нужно изменить базовую структуру, это указывает на существенную проблему проектирования: если вы правильно используете интерфейсы, вам обычно не нужен доступ к базовой структуре.
3. @mkopriva Да, я имею в виду незарегистрированный. Нет, я не хочу вносить изменения в свой собственный пакет.
4. @Адриан, я понимаю, спасибо.
Ответ №1:
Ваш интерфейс уже предоставляет changeName
метод, но его реализация не изменяет имя получателя person
, он возвращает новое person
с тем же возрастом, что и получатель, и переданное имя.
Идея интерфейса заключается в том, что коду, который взаимодействует с интерфейсом, не нужно знать особенности реализации. Но если changeName
возвращает a *person
, вы уже заставляете вызывающего абонента знать детали реализации.
Так почему бы не реализовать изменение имени таким образом ?
func (p *person) changeName(n string) {
p.name = n
}
Комментарии:
1. Спасибо Дэниелу за ваш ответ, на самом деле я не контролирую реализацию
changeName
в моем случае, но реализация этой внешней библиотеки, которую я использую, возвращает нового человека того же возраста, что и получатель, и переданное имя.