2016-07-12 7 views
1

Kann mir jemand erklären, warum diese einzelne Zeile Block mit einem impliziten return kompiliert:Swift Block Syntax Versagen abzuleiten Typ

let r = withUnsafePointer(&msg) { 
    dn_expand(UnsafePointer($0), eomorig: UnsafePointer($0).advancedBy(msg.count), comp_dn: UnsafePointer($0).advancedBy(offset), exp_dn: &buf, length: buf.count) 
} 

aber diese Version Refactoring, wo der einzige Unterschied die mehrere Anrufe zu UnsafePointer($0) zu vermeiden, ist nicht :

let s = withUnsafePointer(&msg) { 
    let p = UnsafePointer($0) 
    return dn_expand(p, eomorig: p.advancedBy(msg.count), comp_dn: p.advancedBy(offset), exp_dn: &buf, length: buf.count) 
} 

mit Fehlermeldung:

Cannot convert value of type 'inout [UInt8]' (aka 'inout Array<UInt8>') to expected argument type 'inout _'

Die dn_function genannt wird, ist nur eine triviale Wrapper um dn_expand von libresolv:

public static func dn_expand(msg: UnsafePointer<UInt8>, eomorig: UnsafePointer<UInt8>, comp_dn: UnsafePointer<UInt8>, exp_dn: UnsafeMutablePointer<CChar>, length: Int) -> Int { 
    return Int(res_9_dn_expand(msg, eomorig, comp_dn, exp_dn, Int32(length))) 
} 
+0

Was die Signatur für ' dn_expand'? –

+2

Der Compiler leitet den Typ eines Abschlusses automatisch nur für * single-expression-closures * oder aus dem * context * ab, vergleiche http://stackoverflow.com/a/34115788/1187415. –

+0

@MartinR Ich vermutete als solche, aber ich kann nicht den richtigen expliziten Typ selbst bestimmen – Alnitak

Antwort

2

Wie bereits in den Kommentaren, withUnsafePointer() ist nicht der richtige Weg, um einen Zeiger auf das Element zu erhalten Lager. Es kompiliert, aber gibt unerwartete Ergebnisse, wie das folgende Beispiel zeigt:

var msg: [UInt8] = [1, 2, 3, 4] 

func foo(x: UnsafePointer<UInt8>) { 
    print(x[0]) 
} 

withUnsafePointer(&msg) { 
    foo(UnsafePointer($0)) 
} 

Dieser druckt „random“ Zahlen, aber die nicht 1 erwartet. Die richtige Art und Weise ist die withUnsafeBufferPointer() Methode auf dem Array zu nennen:

msg.withUnsafeBufferPointer { 
    foo($0.baseAddress) 
} 

In Ihrem Fall, die

let r = msg.withUnsafeBufferPointer { 
    dn_expand($0.baseAddress, eomorig: $0.baseAddress + $0.count, ...) 
} 

Hier ist der Rückgabetyp des Verschlusses automatisch, weil wird gefolgert, wäre es ein " Single-Expression "Schließung. Wenn der Verschluss mehr als einen Ausdruck enthält, müssen Sie den Typ angeben:

let r = msg.withUnsafeBufferPointer { bufPtr -> Int in 
    let p = bufPtr.baseAddress 
    return dn_expand(p, eomorig: p + msg.count, ...) 
} 

oder lassen Sie den Compiler den Rückgabetyp aus dem Zusammenhang ableiten:

let r: Int = msg.withUnsafeBufferPointer { bufPtr in 
    let p = bufPtr.baseAddress 
    return dn_expand(p, eomorig: p + msg.count, ...) 
} 
+0

Danke (und auch @ingoem). Aus irgendeinem Grund habe ich nie zuvor 'Array.withUnsafeBufferPointer() 'gefunden! : p – Alnitak