Вам просто нужно родовое дополнение:
func +<A: Angle>(lhs: A, rhs: Angle) -> A {
return A(rawRadians: lhs.rawRadians + rhs.rawRadians)
}
Таким образом, дополнение будет возвращать любой тип на LHS.
Вообще говоря, если вы используете dynamicType
, вы, вероятно, сражаетесь с Swift. Swift больше полагается на генерики и протоколы (т. Е. Информацию о статическом типе во время компиляции), а не на динамическую отправку (т. Е. Информацию о динамическом типе во время выполнения).
В этом коде, как вы говорите, A
является заполнителем для «определенного типа, который соответствует Angle
, который будет определен во время компиляции». Таким образом, в первом примере:
Degrees(180) + Rotations(0.25) --> Degrees(270)
Это фактически вызывает специальную функцию +<Degrees>
. А это:
Rotations(0.25) + Radians(M_PI) -> Rotations(0.75)
называет (логически) другую функцию под названием +<Rotations>
. Компилятор может выбрать оптимизацию этих функций в одну функцию, но логически они являются независимыми функциями, созданными во время компиляции. Это в основном ярлык для записи addDegrees(Degrees, Angle)
и addRotations(Rotations, Angle)
вручную.
Теперь, на ваш вопрос о функции, которая принимает два угла и возвращает .... ну, что? Если вы хотите вернуть Angle
в этом случае, это легко, и точно совпадает с оригинальной подписью:
func +(lhs: Angle, rhs: Angle) -> Angle {
return Radians(rawRadians: lhs.rawRadians + rhs.rawRadians)
}
«Но ...» вы говорите «который возвращает Radians
.» Нет, нет. Он возвращает Angle
. Вы можете делать все, что угодно, «под углом». Детали реализации непрозрачны, как и должно быть. Если вам небезразлично, что базовая структура данных - это Radians
, вы почти наверняка делаете что-то неправильно.
ОК, есть один боковой корпус, где может быть полезно знать это, и это, если вы печатаете вещи в зависимости от того, как вы их отправляете.Поэтому, если пользователь дал вам информацию о степени, чтобы начать, вы хотите распечатать все в градусах (используя метод description
, который вы не указали). И, возможно, что это стоит делать в этом конкретном case.If вы хотите, исходный код был очень близок:
func +(lhs: Angle, rhs: Angle) -> Angle {
return lhs.dynamicType.init(rawRadians: lhs.rawRadians + rhs.rawRadians)
}
Но очень важно, чтобы понять, что это не соответствует Вашему запросу, чтобы иметь «аргумент LHS диктовать тип возврата. " Это заставляет аргумент lhs диктовать возврат реализации. Возврат тип всегда Angle
. Если вы хотите изменить возврат типа, вам необходимо использовать генерики.
Awesome! Это работает. Если у вас есть шанс, я был бы признателен, если бы вы добавили немного объяснений в том, как компилятор интерпретирует общую часть синтаксиса. Я смутно понимаю дженерики, но этого недостаточно. Является ли по существу заполнителем для любого типа, который мог бы там, и вы ограничиваете допустимые карты через часть ': Angle'? –
Я говорил слишком рано. Я только что обнаружил проблему с этим. Если у меня есть две переменные, объявленные типом 'Angle', которые не уточняются до одной из моих трех соответствующих структур, тогда компилятор говорит, что« двоичный оператор «+» не может применяться между двумя операндами «Угол» –