Как отбрасывать из точечного объекта в объект подпункта?
blockquote>Вы не можете; если только
point
не имеет оператора преобразования, илиsubpoint
имеет конструктор преобразования, и в этом случае типы объектов могут быть преобразованы без необходимости приведения.Вы можете использовать из
point
ссылка (или указатель) на ссылкуsubpoint
(или указатель), если упомянутый объект действительно имеет типsubpoint
:subpoint s; point & a = s; subpoint & b1 = static_cast<subpoint&>(a); subpoint & b2 = dynamic_cast<subpoint&>(a);
Первый (
static_cast
) более опасен; нет проверки, что преобразование действительно, поэтому, еслиa
не ссылается наsubpoint
, то использованиеb1
будет иметь неопределенное поведение.Второй (
dynamic_cast
) является безопаснее, но будет работать, только еслиpoint
является полиморфным (то есть, если он имеет виртуальную функцию). Еслиa
ссылается на объект несовместимого типа, тогда он выдает исключение.
Это очень похоже на вопрос, на который я только что ответил: https://stackoverflow.com/a/12990540/727643
Короткий ответ: вы правы. Кусочек структур не равен фрагменту интерфейса, реализуемого структурой.
A []Person
и []Model
имеют разные макеты памяти. Это связано с тем, что типы, на которых они расположены, имеют разные макеты памяти. A Model
- значение интерфейса, что означает, что в памяти это два слова по размеру. Одно слово для информации о типе, другое для данных. A Person
- это структура, размер которой зависит от полей, которые он содержит. Чтобы преобразовать из []Person
в []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())
}
Поскольку Стивен уже ответил на вопрос, и вы начинающий, я подчеркиваю, что даю советы.
. Лучше работать с интерфейсами go - это не иметь конструктора, возвращающего интерфейс, как вы могли бы использовать с другими языками, такими как java, но иметь конструктор для каждого объекта независимо, поскольку они реализуют интерфейс неявно.
Вместо
newModel(type string) Model { ... }
вы должны сделать
newPerson() *Person { ... }
newPolitician() *Politician { ... }
с Person
и Politician
, реализующими методы Model
. Вы все равно можете использовать Person
или Politician
везде, где принят Model
, но вы также можете реализовать другие интерфейсы.
С помощью вашего метода вы будете ограничены Model
, пока не выполните ручное преобразование в другой тип интерфейса.
Предположим, что у меня есть Person
, который реализует метод Walk()
и Model
реализует ShowOff()
, следующее не будет работать прямо:
newModel("person").ShowOff()
newModel("person").Walk() // Does not compile, Model has no method Walk
Однако это будет:
newPerson().ShowOff()
newPerson().Walk()
/api/{collection}
будет динамически взаимодействовать с запрашиваемой коллекцией. Можете ли вы предложить альтернативное решение без явного тестирования запрошенного сбор через несколько функций? Я предполагаю, что я ищу способ указать общий тип возврата, не теряя знания своего типа.
– Jon L.
21 October 2012 в 05:45
interface{}
, проблема в том, что вам нужно выполнять утверждения типа времени выполнения вместо проверки типа компилятора. Общее решение для name -> object
без утверждений времени исполнения возможно только с использованием дженериков, которые не поддерживаются. Поэтому, если вы это сделаете, вам нужно жить с отражением или недостатками вашего решения.
– nemo
21 October 2012 в 15:13
Как уже ответили другие, [] T - особый тип. Я хотел бы добавить, что простая простая утилита может использоваться для их общего преобразования.
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
}
Теперь вы можете использовать его следующим образом:
ToIntf([]int{1,2,3})
Типы T и [] T являются различными типами, и они отличаются друг от друга, даже если они удовлетворяют одному и тому же интерфейсу. IOW, каждый тип, удовлетворяющий модели, должен реализовать все методы модели самостоятельно - приемником метода может быть только один конкретный тип.