Это неправильное понимание того, что такое дженерики. Эта строка кода не делает то, что вы ожидаете:
func array<E>() -> Array<E>? {
Это говорит, что "для любого типа, переданного вызывающей стороной, эта функция возвратит необязательный массив этого тип." Независимо от типа. Ваша функция возвращает [String]?
или [Int]?
, которые являются только двумя возможными типами. Ваша функция обещала, что может обработать что угодно .
Типы - это обещания, и вам нужно сдержать свое обещание здесь. У вас есть функция, которая возвращает либо массив строк или массив Int. Вы можете express "либо", используя перечисление:
enum ReturnType {
case string([String])
case int([Int])
}
И тогда ваша функция возвращает:
func array() -> ReturnType {
if returnString {
return .string(["Hello World"])
} else {
return .int([1])
}
}
И ваш вызывающий код получает .string(["Hello World"])
:
let myClass = MyClass(returnString: true)
let myStrings = myClass.array()
Если вместо myStrings
иногда [String]
, а иногда [Int]
, что будет делать строка кода myStrings[0].count
(в Int нет .count
)? Должно ли оно взломать sh? Весь смысл типов * stati c состоит в том, чтобы определить, является ли что-то безопасным во время компиляции, а не просто сбой во время выполнения.
Вы также можете изменить свое обещание. Например, вы можете сказать «это возвращает массив вещей, которые могут быть преобразованы в строки».
func array() -> [CustomStringConvertible] {
if returnString {
return ["Hello World"]
} else {
return [1]
}
}
И тогда вы можете смело вызывать description
для результатов. Или вы можете назначить свой собственный протокол, обеспечивающий любые необходимые вам функции.