Как написать функцию, которая принимает аргументы универсального типа, но возвращает другой тип в зависимости от типа универсального объекта?

Я пытаюсь написать базовую функцию интерполяции в swift3. Однако я получаю много ошибок. Это явно неправильный способ использования дженериков, но, может быть, у меня есть фундаментальное непонимание их применения?

class func interpolate<T>(from: T, to: T, progress: CGFloat) -> T
{
    // Safety
    assert(progress >= 0 && progress <= 1, "Invalid progress value: \(progress)")

    if let from = from as? CGFloat, let to = to as? CGFloat
    {
        return from + (to - from) * progress // No + candidates produce the expected contextual result type 'T'
    }
    if let from = from as? CGPoint, let to = to as? CGPoint
    {
        var returnPoint = CGPoint()
        returnPoint.x     = from.x + (to.x-from.x) * progress
        returnPoint.y     = from.y + (to.y-from.y) * progress
        return returnPoint // Cannot convert return expression of type 'CGPoint' to return type 'T'
    }
    if let from = from as? CGRect, let to = to as? CGRect
    {
        var returnRect = CGRect()
        returnRect.origin.x     = from.origin.x + (to.origin.x-from.origin.x) * progress
        returnRect.origin.y     = from.origin.y + (to.origin.y-from.origin.y) * progress
        returnRect.size.width   = from.size.width + (to.size.width-from.size.width) * progress
        returnRect.size.height  = from.size.height + (to.size.height-from.size.height) * progress
        return returnRect // Cannot convert return expression of type 'CGRect' to return type 'T'
    }

    return nil // Nil is incompatible with return type 'T'
}

person GoldenJoe    schedule 31.07.2016    source источник
comment
Пробовали ли вы общий подход, предложенный в stackoverflow.com/questions/38652237/?   -  person Martin R    schedule 31.07.2016
comment
Этот ответ был просто более длинным способом расширения интересующих меня классов, чтобы иметь функцию интерполяции, что я и делаю сейчас в качестве временной меры. Это также не ответило на вопрос, почему то, что я пробовал, не работает.   -  person GoldenJoe    schedule 31.07.2016


Ответы (1)


Универсальная функция полезна, когда одни и те же операции нужно выполнять над несколькими разными типами. Это в основном то, что у вас есть здесь. Проблема в том, что у вас нет операций, определенных для двух интересующих вас типов, а именно CGPoint и CGRect.

Если вы создаете отдельные функции для сложения, вычитания и умножения этих типов, вы можете заставить эту общую функцию работать. Было бы проще до

class func interpolate<T>(from: T, to: T, progress: CGFloat) -> T
{
    // Safety
    assert(0.0...1.0 ~= progress, "Invalid progress value: \(progress)")

    return from + (to - from) * progress
}
person jscs    schedule 31.07.2016
comment
Будет ли считаться плохим шаблоном просто перегрузить операторы + и - в классе интерполяции, чтобы я мог использовать эту упрощенную версию? Есть ли способ безопасно вырваться, если переданный тип не поддерживает операторы? - person GoldenJoe; 31.07.2016
comment
Редактировать: Неважно, попытка перегрузить операторы дает мне: // Нет + кандидатов дают ожидаемый контекстуальный тип результата 'T' - person GoldenJoe; 31.07.2016