Как вы приведете UInt64 к Int64?

Попытка вызвать dispatch_time в Swift делает мою голову, вот почему:

 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 10 * NSEC_PER_SEC), dispatch_get_main_queue(), {
            doSomething()
            })

В результате возникает ошибка: "Не удалось найти перегрузку для" * ", которая принимает предоставленные аргументы".

NSEC_PER_SEC - это UInt64, поэтому время для некоторых экспериментов:

let x:UInt64 = 1000
let m:Int64 = 10 * x

Результаты в той же ошибке, что и выше

let x:UInt64 = 1000
let m:Int64 = 10 * (Int64) x

Результаты в "Последовательных утверждениях в строке должны быть разделены знаком"; "

let x:UInt64 = 1000
let m:Int64 = 10 * ((Int64) x)

Результаты в "Ожидаемый", "разделитель"

let x:UInt64 = 1000
let m:Int64 = (Int64)10 * (Int64) x

Результаты в "Последовательных утверждениях в строке должны быть разделены знаком"; "

И т. Д.

Будь ты проклят компилятор Swift, я сдаюсь. Как преобразовать UInt64 в Int64 и / или как вы используете dispatch_time в swift?

6 ответов

Решение

Кастинг UInt64 для Int64 не безопасно, так как UInt64 может иметь число больше Int64.max, что приведет к переполнению.

Вот фрагмент для преобразования UInt64 в Int64 и наоборот:

// Extension for 64-bit integer signed <-> unsigned conversion

extension Int64 {
    var unsigned: UInt64 {
        let valuePointer = UnsafeMutablePointer<Int64>.allocate(capacity: 1)
        defer {
            valuePointer.deallocate(capacity: 1)
        }

        valuePointer.pointee = self

        return valuePointer.withMemoryRebound(to: UInt64.self, capacity: 1) { $0.pointee }
    }
}

extension UInt64 {
    var signed: Int64 {
        let valuePointer = UnsafeMutablePointer<UInt64>.allocate(capacity: 1)
        defer {
            valuePointer.deallocate(capacity: 1)
        }

        valuePointer.pointee = self

        return valuePointer.withMemoryRebound(to: Int64.self, capacity: 1) { $0.pointee }
    }
}

Это просто интерпретирует двоичные данные UInt64 как Int64то есть числа больше чем Int64.max будет отрицательным из-за знакового бита в самом значимом бите 64-битного целого числа.

Если вам нужны только натуральные числа, просто получите абсолютное значение.

РЕДАКТИРОВАТЬ: В зависимости от поведения, вы можете получить абсолютное значение, или:

if currentValue < 0 {
    return Int64.max + currentValue + 1
} else {
    return currentValue
}

Последний вариант аналогичен удалению знака. Пример:

// Using an 8-bit integer for simplicity

// currentValue
0b1111_1111 // If this is interpreted as Int8, this is -1.

// Strip sign bit
0b0111_1111 // As Int8, this is 127. To get this we can add Int8.max

// Int8.max + currentValue + 1
127 + (-1) + 1 = 127

Чтобы построить Int64 используя биты UInt64, использовать init видел здесь: https://developer.apple.com/reference/swift/int64/1538466-init

let myInt64 = Int64(bitPattern: myUInt64)

Вы можете "приводить" между различными целочисленными типами, инициализируя новое целое число нужным вам типом:

let uint:UInt64 = 1234
let int:Int64 = Int64(uint)

Это, вероятно, не проблема в вашем конкретном случае, но стоит отметить, что разные целочисленные типы имеют разные диапазоны, и вы можете получить сбой вне диапазона, если попытаетесь конвертировать между целыми числами разных типов:

let bigUInt:UInt64 = UInt64(Int64.max) - 1      // 9,223,372,036,854,775,806
let bigInt:Int64 = Int64(bigUInt)               // no problem

let biggerUInt:UInt64 = UInt64(Int64.max) + 1   // 9,223,372,036,854,775,808
let biggerInt:Int64 = Int64(biggerUInt)         // crash!

Каждый целочисленный тип имеет .max а также .min Свойства класса, которые вы можете использовать для проверки диапазонов:

if (biggerUInt <= UInt64(Int64.max)) {
    let biggerInt:Int64 = Int64(biggerUInt)     // safe!
}

Попробуй это:

let x:UInt64 = 1000 // 1,000
let m:Int64 = 10 * Int64(x) // 10,000

или даже:

let x:UInt64 = 1000 // 1,000
let m = 10 * Int64(x) // 10,000
let n = Int64(10 * x) // 10,000
let y = Int64(x) // 1,000, as Int64 (as per @Bill's question)

Это не столько кастинг, сколько инициализация отдельным типом...

Лучшее решение для конвертации:

UInt64 Int64_2_UInt64(Int64 Value)
{
     return (((UInt64)((UInt32)((UInt64)Value >> 32))) << 32) 
        | (UInt64)((UInt32)((UInt64)Value & 0x0ffffffff));           
}

Int64 UInt64_2_Int64(UInt64 Value)
{
    return (Int64)((((Int64)(UInt32)((UInt64)Value >> 32)) << 32) 
       | (Int64)((UInt32)((UInt64)Value & 0x0ffffffff)));           
}

Простое решение для Swift 3 - это встроенная функция, которая заботится о переполнениях и управлении буфером.

var a:UInt64 = 1234567890
var b:Int64 = numericCast(a)
Другие вопросы по тегам