У меня возникла проблема с использованием статических функций + и * в расширении Swift. Я просто хочу, чтобы + был * и * был +. Когда я использую только оператор +, он работает нормально, но когда я включаю оба оператора, я сталкиваюсь с бесконечным циклом.
Работает отлично
extension Int {
static func + (left: Int, right: Int) -> Int {
return (left * right)
}
}
// 12
print(3 + 4)
// 12
print(3 * 4)
Теперь переходим в бесконечный цикл
extension Int {
static func + (left: Int, right: Int) -> Int {
return (left * right)
}
static func * (left: Int, right: Int) -> Int {
return (left + right)
}
}
print(3 + 4)
print(3 * 4)
Мы ценим любые предложения.
Классный трюк для отладки: используйте print(#function), см. ниже в комментариях.
Вопрос: Когда вы делаете return (left + right)
(left + right)
какая операция должна быть? «Настоящий +» или переопределенный «+»? Это ваша проблема.
Измените умножение на Int(Double(left) + Double(right))
, и это «исправит», понимаете, почему?
@Larme Я смотрел на все это примерно так: внутри тела + и * каким-то образом не меняются (не знаю, как создается +/*). Когда я говорю «статическая функция +», я надеялся, что, возможно, я сделаю какое-то затенение. Итак, + и *, поставляемые с языком, возможно, не изменились, и мое расширение каким-то образом идет поверх этого, я не знаю...
@JoakimDanielson, это означает, что есть + для Int и один для double? Или что-то вроде того, как метод разрешен внутри класса с тем же именем и разными типами? Значит, у каждого типа может быть несколько плюсов? (Не для каждого типа, но, возможно, для каждой версии отдельного аргумента). Но я полагаю, что + — это инфикс, верно?
Похоже, print(3.0 + 4.0) возвращает 7.0. Я хотел сделать это только для Int, а не пропустить Int * и использовать Double, а затем преобразовать его обратно в Int. Возможно, позже я расширию функцию или что-то еще, что выполняет преобразование, и эта штука больше не будет работать.
Мое предложение было для int, так что все равно сделайте 3 + 4. Просто чтобы проверить, понимаете ли вы, почему у вас бесконечный цикл, верно?
@JoakimDanielson Понятно. Итак, это означает, что + — это функция внутри класса Int, * также является функцией внутри класса Int, теперь я думаю, что происходит: 1. Какая-то взаимная рекурсия? Я думаю, что Swift позволяет это, я определенно использовал это раньше. 2. Все ли в логике и как она переопределяется?
Не знаю почему, но я думаю, что, возможно, здесь есть что-то еще, какие-то глубокие вещи в коде. Может быть, * реализуется с помощью +?
Добавьте print(#function)
в первую строку каждой функции, и вы увидите, что они вызывают друг друга.
Молодец, классная отладка. Похоже, у него нет базового варианта для завершения рекурсии. Опять же, я думаю, что это просто какие-то глубокие вещи, потому что, если я скажу 5 + 3 или 5 * 3, я не достигну базового случая, я предполагаю, что компилятор (или Xcode или что-то еще) делает это с помощью некоторых алгоритмов.
ааааа, базовый случай умножения отличается от сложения, так вот почему это делается, потому что я поменял местами эти 2?
Речь идет не о базовом случае, а о вызове между * и +? так * вызывает мой * не тот, который указан в коде сборки, и то же самое происходит с +? Значит, эти двое звонят друг другу, и никто из них не назовет код, который пришел со Swift?
Я только что увидел, что вы это сказали, и думаю, вы отредактировали свой комментарий, потому что не думаю, что раньше так было.
@JoakimDanielson Есть ли способ изменить фактические + и * и не использовать другой инфиксный оператор, потому что здесь вы делаете что-то с функциями, а не со значениями. Я не говорю, что нужно иметь локальную копию +, а затем использовать какую-то логику, я говорю непосредственно о +.
Y'in + вы вызываете *, а в * вы вызываете +: это будет повторяться вечно, поскольку одна функция вызывает другую.
Пожалуйста, опубликуйте ответ, если у вас есть лучший вариант (хочу изменить встроенный + и встроенный *).
infix operator ++
infix operator **
extension Int {
static funC++ (left: Int, right: Int) -> Int {
return (left * right)
}
static func ** (left: Int, right: Int) -> Int {
return (left + right)
}
}
// 12
print(3 ++ 4)
// 7
print(3 ** 4)
Расширение внутри функции не допускается (объявление действительно только в области файла), поэтому Swift не позволяет переназначать или затенять операторов в локальных областях, поэтому, если кто-то1 предложил решение, мы очень ценим.
Два оператора, объявленные вами в расширениях, продолжают звонить друг другу. Самый простой способ избежать этого — не использовать +
или *
в телах этих операторов.
Нам нужен способ вызова встроенных +
и *
даже при наличии расширения. К счастью, +
и *
в Int
являются протокольными свидетелями требований +
и *
в Числовом протоколе. Мы можем вызвать +
и *
через Numeric
:
// * and + in these functions will not resolve to the ones you declared in the extension
func add<T: Numeric>(_ lhs: T, _ rhs: T) -> T {
lhs + rhs
}
func multiply<T: Numeric>(_ lhs: T, _ rhs: T) -> T {
lhs * rhs
}
// your custom + and * operators can be implemented with the above functions
extension Int {
static func + (left: Int, right: Int) -> Int {
return multiply(left, right)
}
static func * (left: Int, right: Int) -> Int {
return add(left, right)
}
}
Конечно, тот же подход не сработает, если вы хотите поменять местами +
и *
для каждого типа Numeric
, но этот трюк работает для любого типа, который «более специфичен», чем Numeric
, например FloatingPoint
, SignedNumeric
и т. д.
Итак, вот то, что я искал:
import Foundation
extension Int {
static func + (left: Int, right: Int) -> Int {
return (left &* right)
}
static func * (left: Int, right: Int) -> Int {
return (left &+ right)
}
}
// 12
print(3 + 4)
// 7
print(3 * 4)
«В Swift операторы &+, &- и &* предоставляют арифметические операции, которые не перехватывают переполнение, а вместо этого оборачиваются с использованием представления дополнения до двух. Это имитирует, сколько языков более низкого уровня (например, C) обрабатывают арифметическое переполнение и как работают аппаратные инструкции для арифметических операций».
Я понятия не имею, что означает приведенное выше объяснение, если кто-нибудь сможет объяснить это подробно, было бы здорово. Я знаю, что &* есть умножение с защитой от переполнения, но что оно делает и как оно используется Swift, я не знаю. Спасибо (просто прокомментируйте под этим ответом).
Посмотрите это видео Быстрое преобразование чисел с плавающей запятой Cpp — Кассио Нери — C++, сейчас 2024 год там хорошие вещи. Может быть, каким-то образом это и работает. Если бы кто-нибудь мог рассказать об этом подробнее, это было бы потрясающе.
Некоторая дополнительная информация: Операторы переполнения , и это тоже Таблица 4-битной двоичной системы с методом дополнения ДВА
- &*: оператор &* выполняет умножение и допускает переполнение. В Swift, когда целочисленные операции переполняются, результат оборачивается с использованием арифметики дополнения до двух. Это означает, что если результат превышает максимально представимое значение, он переходит к минимально представимому значению, и наоборот.
- &+: Аналогично оператор &+ выполняет сложение и допускает переполнение. Он также использует арифметику с дополнением до двух, если результат превышает представимый диапазон типа.
Более подробная информация приветствуется!
Как-то мне нужно сохранить локальный +? Похоже на: «Поменять местами два числа»?