Это примерно дисперсия .
(Поскольку Kotlin различает изменяемые и неизменяемые списки, это строже, чем Java, поэтому вы не всегда можете сравнивать напрямую. )
Предположим, у вас есть ссылка на MutableList<out MyMarkerInterface>
. Этот параметр эквивалентен Java <? extends MyMarkerInterface>
и означает, что у вас есть изменяемый список MyMarkerInterface
или некоторый подтип . Но вы не знаете , какой подтип; это может быть любой тип, реализующий ваш интерфейс.
Это может быть изменяемый список MyImplementingClassA
; таким образом, вы явно не можете добавить экземпляр MyImplementingClassB
, не рискуя нарушить его безопасность типов. Ни наоборот. На самом деле, не зная больше о его типе, небезопасно добавлять что-нибудь к этому . Вот почему Kotlin не позволит вам. (Это делается путем вывода типа Nothing
, который является «нижним» и не имеет значений.)
Однако, если вы хотите получить значение из списка, вы знаете, что это какой-то подтип MyMarkerInterface
, поэтому вы можете с радостью рассматривать его как MyMarkerInterface
ссылку.
Вот почему out
дисперсия означает список продюсер : он может создавать значения для вас безопасно, но не может использовать значения, потому что ни один тип не будет безопасным.
И это полная противоположность для in
дисперсия, которая эквивалентна Java ? super
.
(что, конечно, составляет PECS . Это точное выражение применимо только к Java - Kotlin эквивалент - «Producer Out, Consumer In», что, вероятно, слишком очевидно, чтобы использовать аббревиатуру! - но принцип тот же.)
Единственный безопасный способ быть обоими продюсерами и потребитель должен быть инвариантом : обычный старый MutableList<MyMarkerInterface>
. Таким образом, вы знаете, что вы можете получить MyMarkerInterface
значения из и положить MyMarkerInterface
значения в.
Вещи разные для List
s, которые неизменны в Kotlin , (Или, скорее, вы не можете изменить их через эту ссылку ; возможно, вы сможете каким-то другим способом.) Поскольку эта ссылка не позволит вам ввести значения, a List
не выступает в роли потребителя, только производитель, поэтому для этого вполне подойдет out
дисперсия .
-
Ваш вопрос не дает никаких подробностей, но вы упомянули инициализацию , Вероятно, наиболее распространенным является создание List
со всеми значениями, которые он будет иметь заранее - либо путем вызова listOf()
, либо с помощью конструктора, либо в результате map()
или аналогичная операция.
Однако вы также можете создать некоторый тип MutableList
, настроить его по мере необходимости, а затем увеличить его до List
(который является суперинтерфейсом MutableList
), например:
val ml = ArrayList<MyImplementingClassA>()
// …some computation which calls ml.add()…
val l = ml as List<out MyMarkerInterface>
… хотя на практике вам обычно не нужна эта последняя строка; Kotlin знает , что List
s имеют out
дисперсию, и поэтому при необходимости он автоматически повышается с ml
до List<out MyMarkerInterface>
.