구조체 조각! = 구현하는 인터페이스 조각?
Model
struct에 의해 구현 된 인터페이스 가 Person
있습니다.
모델 인스턴스를 얻기 위해 다음과 같은 도우미 함수가 있습니다.
func newModel(c string) Model {
switch c {
case "person":
return newPerson()
}
return nil
}
func newPerson() *Person {
return &Person{}
}
위의 접근 방식을 사용하면 적절한 형식의 Person 인스턴스를 반환 할 수 있습니다 (나중에 동일한 접근 방식으로 쉽게 새 모델을 추가 할 수 있음).
모델 조각을 반환하기 위해 비슷한 작업을 시도 할 때 오류가 발생합니다. 암호:
func newModels(c string) []Model {
switch c {
case "person":
return newPersons()
}
return nil
}
func newPersons() *[]Person {
var models []Person
return &models
}
Go는 다음과 같이 불평합니다. cannot use newPersons() (type []Person) as type []Model in return argument
내 목표는 요청 어떤 모델 유형의 슬라이스를 반환하는 것입니다 (여부 []Person
, []FutureModel
, []Terminator2000
, w / E). 내가 무엇을 놓치고 있으며 어떻게 이러한 솔루션을 올바르게 구현할 수 있습니까?
이것은 방금 답변 한 질문과 매우 유사합니다. https://stackoverflow.com/a/12990540/727643
짧은 대답은 당신이 맞다는 것입니다. 구조체 조각은 구조체가 구현하는 인터페이스 조각과 동일하지 않습니다.
A []Person
와 a []Model
는 메모리 레이아웃이 다릅니다. 이는 슬라이스 유형이 메모리 레이아웃이 다르기 때문입니다. A Model
는 메모리에서 크기가 두 단어임을 의미하는 인터페이스 값입니다. 유형 정보에 대한 한 단어, 데이터에 대한 다른 단어. A Person
는 크기가 포함 된 필드에 따라 달라지는 구조체입니다. A로부터 변환하기 위해 []Person
A를 []Model
, 당신은 배열을 통해 루프가 필요하고 각 요소에 대한 형식 변환을 할 것입니다.
이 변환은 O (n) 작업이고 새 슬라이스가 생성되는 결과를 가져 오므로 Go는이를 암시 적으로 거부합니다. 다음 코드를 사용하여 명시 적으로 수행 할 수 있습니다.
models := make([]Model, len(persons))
for i, v := range persons {
models[i] = Model(v)
}
return models
그리고 dskinner가 지적했듯이 슬라이스에 대한 포인터가 아닌 포인터 슬라이스를 원할 가능성이 큽니다. 슬라이스에 대한 포인터는 일반적으로 필요하지 않습니다.
*[]Person // pointer to slice
[]*Person // slice of pointers
아마도 이것은 반환 유형의 문제 *[]Person
일 수 있습니다. 실제로 []*Person
슬라이스의 각 인덱스가에 대한 참조 Person
이고 슬라이스 []
자체가 배열에 대한 참조임을 참조해야합니다.
다음 예를 확인하십시오.
package main
import (
"fmt"
)
type Model interface {
Name() string
}
type Person struct {}
func (p *Person) Name() string {
return "Me"
}
func NewPersons() (models []*Person) {
return models
}
func main() {
var p Model
p = new(Person)
fmt.Println(p.Name())
arr := NewPersons()
arr = append(arr, new(Person))
fmt.Println(arr[0].Name())
}
Stephen이 이미 질문에 답했고 당신은 초보자이기 때문에 조언을 제공하는 것을 강조합니다.
go의 인터페이스로 작업하는 더 좋은 방법은 Java와 같은 다른 언어에서 익숙한 것처럼 인터페이스를 반환하는 생성자를 가지지 않고 인터페이스를 암시 적으로 구현하기 때문에 각 객체에 대해 독립적으로 생성자를 갖는 것입니다.
대신에
newModel(type string) Model { ... }
당신은해야합니다
newPerson() *Person { ... }
newPolitician() *Politician { ... }
with Person
and Politician
both implementing the methods of Model
. You can still use Person
or Politician
everywhere where a Model
is accepted, but you can also implement other interfaces.
With your method you would be limited to Model
until you do a manual conversion to another interface type.
Suppose I have a Person
which implements the method Walk()
and a Model
implements ShowOff()
, the following would not work straight forward:
newModel("person").ShowOff()
newModel("person").Walk() // Does not compile, Model has no method Walk
However this would:
newPerson().ShowOff()
newPerson().Walk()
Types T and []T are distinct types and distinct are their methods as well, even when satisfying the same interface. IOW, every type satisfying Model must implement all of the Model's methods by itself - the method receiver can be only one specific type.
As others have already answered, []T is a distinct type. I'd just like to add that a simple utility can be used to convert them generically.
import "reflect"
// Convert a slice or array of a specific type to array of interface{}
func ToIntf(s interface{}) []interface{} {
v := reflect.ValueOf(s)
// There is no need to check, we want to panic if it's not slice or array
intf := make([]interface{}, v.Len())
for i := 0; i < v.Len(); i++ {
intf[i] = v.Index(i).Interface()
}
return intf
}
Now, you can use it like this:
ToIntf([]int{1,2,3})
Even if Go's implementation allowed this, it's unfortunately unsound: You can't assign a []Person
to a variable of type []Model
because a []Model
has different capabilities. For example, suppose we also have Animal
which implements Model
:
var people []Person = ...
var models []Model = people // not allowed in real Go
models[0] = Animal{..} // ???
var person Person = people[0] // !!!
If we allow line 2, then line 3 should also work because models
can perfectly well store an Animal
. And line 4 should still work because people
stores Person
s. But then we end up with a variable of type Person
holding an Animal
!
Java actually allows the equivalent of line 2, and it's widely considered a mistake. (The error is caught at run time; line 3 would throw an ArrayStoreException
.)
ReferenceURL : https://stackoverflow.com/questions/12994679/slice-of-struct-slice-of-interface-it-implements
'IT박스' 카테고리의 다른 글
Python의 문자열에서 하위 문자열이 몇 번 발생하는지 확인 (0) | 2021.01.07 |
---|---|
여러 인수에 대한 cmd.exe의 올바른 인용 (0) | 2021.01.07 |
인터페이스가없는 클래스를 어떻게 모의합니까? (0) | 2021.01.07 |
SQL Server 2005 dbo 로그인 이름 변경 방법 (0) | 2021.01.07 |
.gitignore 파일의 경로에 차이가 있습니까? (0) | 2021.01.07 |