2015-06-21 18 views
8

Làm cách nào để khai báo và sử dụng loại công đoàn C trong Swift?Loại công đoàn trong Swift?

tôi đã cố gắng:

var value: union { 
     var output: CLongLong 
     var input: [CInt] 
    } 

nhưng nó không hoạt động ...

CẬP NHẬT: Tôi muốn sử dụng kết hợp để chia một 8 bytes number-2 x 4 bytes number.

+0

Không có hỗ trợ trực tiếp của các công đoàn trong Swift, nhưng bạn có thể sử dụng liệt kê để hoàn thành yêu cầu của mình. – Amit89

+2

Các công đoàn bị phân biệt bởi mọi tiêu chuẩn mã hóa C và C++ đều biết đến con người vì chúng thường được sử dụng để viết mã không di động. Nếu bạn có một sự lựa chọn trong vấn đề, không bao giờ sử dụng một 'union' trong C, và trong mọi trường hợp, giải nén bất kỳ dữ liệu nào được chứa bên trong với các toán tử bit-wise. – marko

+0

@marko, tôi sẽ không đồng ý với tiền đề của bạn. Ví dụ, khi nhận được một tin nhắn, trong đó thông điệp có thể có một vài định dạng khác nhau, nó hầu như luôn được thực hiện như một sự kết hợp của các định dạng đó, thường là trường đầu tiên, không tiêu đề, cho biết loại thông điệp nào được chứa trong phần còn lại của tin nhắn, nơi phần còn lại của tin nhắn được định nghĩa là liên minh của tất cả các loại tin nhắn. – user3629249

Trả lời

10

Khi tài liệu của Apple Swift, Enumerations có thể làm điều tương tự và nhiều hơn nữa.

Ngoài ra, enumeration thành viên có thể chỉ định giá trị đi kèm của bất kỳ loại phải được lưu trữ cùng với mỗi giá trị thành viên khác nhau, nhiều càng unions hoặc variants làm bằng ngôn ngữ khác. Bạn có thể xác định một tập hợp chung của các thành viên có liên quan như một phần của một điều tra, mỗi thành viên có một tập hợp các giá trị khác nhau của các loại thích hợp được liên kết với .

1) Nếu bạn chỉ muốn chia số 8 byte thành số 2 x 4 byte, như bạn có thể đã biết, thì Bitwise Operation của Swift có thể trợ giúp. Cũng giống như

let bigNum: UInt64 = 0x000000700000008 // 
let rightNum = (bigNum & 0xFFFFFFFF) // output 8 
let leftNum = (bigNum >> 32) // output 7 

2) Nếu bạn muốn mô phỏng các hành vi union như C ngôn ngữ, Tôi đã thử một cách như thế này. Mặc dù nó hoạt động, nó trông khủng khiếp.

enum Number { 
    case a(Int) 
    case b(Double) 

    var a:Int{ 
     switch(self) 
     { 
     case .a(let intval): return intval 
     case .b(let doubleValue): return Int(doubleValue) 
     } 
    } 

    var b:Double{ 
     switch(self) 
     { 
     case .a(let intval): return Double(intval) 
     case .b(let doubleValue): return doubleValue 
     } 
    } 
} 
let num = Number.b(5.078) 

println(num.a) // output 5 
println(num.b) // output 5.078 
+3

(2) không giống như một công đoàn C, nó chỉ chuyển đổi giữa double và int. AC union sẽ có cả hai vars chia sẻ cùng một vị trí bộ nhớ, vì vậy lưu trữ 8 byte Double (5.078) chiếm và đọc chúng trở lại như Int sẽ không trả về 5, nhưng 0x40144FDF3B645A1D (4.617,403,338,154,334,749, yikes!) – GoatInTheMachine

+0

Ngữ nghĩa, nó tương tự như liên hiệp. Công đoàn có nghĩa là chia sẻ một vị trí trong bộ nhớ. Một enum nhanh chóng làm điều này, ngoại trừ việc nó thêm vào một byte cho giá trị enum. –

2

Vâng, không có sự hỗ trợ trực tiếp của các công đoàn, trong Swift, nhưng chúng tôi có thể sử dụng điều tra cho mục đích của chúng tôi.

Ex-

enum Algebra { 
    case Addition(Double, Double) 
    case Substraction(Double, Double) 
    case Square(Double) 

    var result : Double { 
    switch(self) 
    { 
    case .Addition(let a, let b): return a + b 
    case .Substraction(let a, let b): return a - b 
    case .Square(let a): return a * a 
    } 
    } 
} 

let solution = Algebra.Addition(5, 3) 
println(solution.result) //Output: 8.0 
+0

Dường như không phải là mục đích tương tự, tôi muốn chia một '8 byte số' thành 2 x '4 byte số' –

+2

Đó là một hoạt động không an toàn mà cố ý không được hỗ trợ trong Swift. Bây giờ rõ ràng những gì bạn muốn làm là tầm thường để đạt được với sự thay đổi và bitwise và hoạt động. Một liệt kê Swift sẽ _never_ cho phép bạn diễn giải lại dữ liệu theo một cách khác. Hoàn toàn có chủ ý. – gnasher729

0

đoàn của bạn không rõ loại của cấu trúc, vì vậy tôi sẽ giả định bạn luôn được bắt nguồn từ đó bối cảnh (bạn luôn biết nếu giá trị là một trong hai output hoặc input). Trong trường hợp đó, tôi sẽ dịch nó thành hai cấu trúc riêng biệt:

struct OutputValue { 
    ... 
} 

struct InputValue { 
    ... 
} 

Nếu bạn muốn các cấu trúc có một số tài sản chung/phương pháp, khai báo một cho nó.

2

Swift không khuyến khích các mẫu lập trình "không an toàn" như union, tuy nhiên, có một giải pháp thay thế. Đó là một chút xấu xí, nhưng ở đây đi (sử dụng Xcode 7.2) ...

struct VariantA { 
    var oneField: Int // 8 bytes 

    struct VariantB { 
     var firstField: UInt32 // first 4 bytes 
     var secondField: UInt32 // second 4 bytes 
    } 

    var variantB: UnsafeMutablePointer<VariantB> { 
     mutating get { 
      func addressOf<U>(something:UnsafePointer<U>) 
       -> UnsafeMutablePointer<VariantB> { 
       return UnsafeMutablePointer<VariantB>(something) 
      } 
      return addressOf(&oneField) 
     } 
    } 
} 

Bây giờ một kiểm tra nhanh của sizeof(VariantA) sẽ hiển thị toàn bộ cấu trúc vẫn chiếm chỉ tám byte (đó là một trong 64-bit số nguyên). Nếu bây giờ chúng ta tạo một thể hiện như thế này var a = VariantA(oneField: 1234567890987654321) thì chúng ta có thể truy vấn các thành phần như thế này a.oneField sẽ trả về giá trị ban đầu 1,234,567,890,987,654,321 và cũng a.variantB.memory.firstField sẽ trả về 2,976,652,465 và a.variantB.memory.secondField sẽ trả về 287,445,236.

Chúng ta có thể thay đổi một trong các thành phần như a.variantB.memory.firstField++ này và sau đó nhận xét rằng điều này thay đổi giá trị ban đầu của a.oneField để 1,234,567,890,987,654,32 như mong đợi.

Các phần xấu cho tôi là sự xuất hiện của các từ "không an toàn", "con trỏ" và .memory. cũng như chức năng trợ giúp addressOf chỉ để khắc phục lỗi trình biên dịch trong Xcode 7.2!

Có lẽ làm việc với các cấu trúc cấp thấp hơn yêu cầu thao tác mức byte như thế này không nên được thực hiện bằng ngôn ngữ cấp cao như Swift. Bạn đã cân nhắc viết phần này của dự án của mình trong một tệp .c? Với tiêu đề cầu nối phù hợp, bạn vẫn có thể thực hiện phần lớn dự án của mình trong Swift.

1

Ở đây tôi xác định MyUnion có hai thành viên có tên fg. Như bạn thấy, union không an toàn và enum với giá trị được liên kết được ưu tiên, mặc dù nó hơi khác so với union.

// Simulate union in C 
// f and g share memory 
struct MyUnion { 
    fileprivate var ivar: UInt32 = 0 // Shared memory, private is better. 

    var f: Float { 
     get { return Float.init(bitPattern: ivar) } 
     set { ivar = newValue.bitPattern } 
    } 
    init(f: Float) { self.f = f } 

    var g: Int32 { 
     get { return Int32(bitPattern: ivar) } 
     set { ivar = UInt32(bitPattern: newValue) } 
    } 
    init(g: Int32) { self.g = g } 
} 

var u = MyUnion(f: 13.12) 
u.f // 13.12 
u.g // 1095887749 
u.ivar // 1095887749 

u.f = -99.123 
u.f // -99.123 
u.g // -1027195142 
u.ivar // 3267772154 

u = MyUnion(g: -1) 
u.f // nan 
u.g // -1 
u.ivar // 4294967295 
Các vấn đề liên quan