Давайте перепишем ваш код следующим образом:
x = 1
y = [x]
z = y * 4
myList = [z] * 3
После этого запустите следующий код, чтобы сделать все более понятным. Что делает код, в основном печатает id
s полученных объектов, которые
Вернуть «идентификатор» объекта
и поможет нам идентифицировать их и проанализировать, что происходит:
print("myList:") for i, subList in enumerate(myList): print("\t[{}]: {}".format(i, id(subList))) for j, elem in enumerate(subList): print("\t\t[{}]: {}".format(j, id(elem)))
И вы получите следующий результат:
x: 1 y: [1] z: [1, 1, 1, 1] myList: [0]: 4300763792 [0]: 4298171528 [1]: 4298171528 [2]: 4298171528 [3]: 4298171528 [1]: 4300763792 [0]: 4298171528 [1]: 4298171528 [2]: 4298171528 [3]: 4298171528 [2]: 4300763792 [0]: 4298171528 [1]: 4298171528 [2]: 4298171528 [3]: 4298171528
Итак, теперь давайте шаг за шагом. У вас есть
x
, который является1
, и единственным списком элементовy
, содержащимx
. Ваш первый шаг -y * 4
, который даст вам новый списокz
, который в основном[x, x, x, x]
, т. Е. Создает новый список, который будет содержать 4 элемента, которые являются ссылками на исходный объектx
. Чистый шаг очень похож. В основном вы делаетеz * 3
, который является[[x, x, x, x]] * 3
и возвращает[[x, x, x, x], [x, x, x, x], [x, x, x, x]]
по той же причине, что и для первого шага.
Хм, вы носите здесь множество взаимно ссылочных универсальных типов, и без использования и примеров использования, я признаю, я почти не представляю, что здесь происходит, и действительно ли это лучший способ представить вашу структуру данных , Я предполагаю, что вы, вероятно, могли бы обойтись без единственного параметра типа, подобного этому:
class Obj<T>
{
constructor(public fields: { [K in keyof T]: Obj<T[K]> }) {
}
public data!: T
}
Но даже если вы сделаете это, у вас все равно будет та же проблема, которая обнаружится, если вы включите более строгий режим [119 ] опции компилятора , такие как --noImplicitAny
или --strict
. Затем вы увидите, что ваше определение recursive
дает вам следующие ошибки:
blockquote>
'recursive' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer.
и
[ 117]
blockquote>Это предполагаемое поведение , когда компилятор не может вывести тип, потому что он определенным образом зависит от самого себя. Предлагаемый способ справиться с этим обычно состоит в том, чтобы дать явную аннотацию типа одной из частей, чтобы разорвать круглость. Это раздражает, потому что вынуждает вас избыточно записывать наборы к вещам, которые были ранее выведены компилятором, но я не знаю, есть ли хороший способ избежать этого.
Вот один из способов сделать это с типами, какими они у вас являются:
// explicit type interface RecursiveObj extends Obj< DataType< { readonly query: RecursiveObj; test: Obj<{}, {}>; } >, { readonly query: RecursiveObj; test: Obj<{}, {}>; }> { } const recursive = new Obj({ // explicitly annotated return type get query(): RecursiveObj { return recursive }, test: new Obj({}) }); // okay now
И вот как я это сделаю с упрощенным
[112 ]Obj<T>
типом I, перечисленным выше:Хорошо, надеюсь, это поможет. Удачи!