Swift: concatenamento opzionale
Il processo di interrogazione, chiamata di proprietà, pedici e metodi su un opzionale che può essere 'nil' è definito come concatenamento opzionale. Il concatenamento facoltativo restituisce due valori:
se l'opzionale contiene un "valore", la chiamata alla sua proprietà correlata, metodi e pedici restituisce valori
se l'opzionale contiene un valore 'nil', tutte le sue proprietà, metodi e pedici correlati restituiscono nil
Poiché più query a metodi, proprietà e pedici sono raggruppate insieme, il fallimento di una catena influenzerà l'intera catena e darà come risultato un valore "nullo".
Concatenamento opzionale come alternativa allo srotolamento forzato
Il concatenamento facoltativo viene specificato dopo il valore facoltativo con "?" per chiamare una proprietà, un metodo o un pedice quando il valore facoltativo restituisce alcuni valori.
Concatenamento opzionale "?" | Accesso a metodi, proprietà e pediciCatenamento opzionale "!" per forzare lo scartamento |
? viene inserito dopo il valore opzionale per chiamare proprietà, metodo o pedice | ! viene posizionato dopo il valore facoltativo per chiamare proprietà, metodo o pedice per forzare lo scartamento del valore |
Non riesce con grazia quando l'opzione è 'zero' | Lo scartamento forzato innesca un errore di runtime quando l'opzione opzionale è 'nil' |
Programma per il concatenamento opzionale con "!"
class ElectionPoll {
var candidate: Pollbooth?
}
lass Pollbooth {
var name = "MP"
}
let cand = ElectionPoll()
let candname = cand.candidate!.name
Quando eseguiamo il programma precedente usando playground, otteniamo il seguente risultato:
fatal error: unexpectedly found nil while unwrapping an Optional value
0 Swift 4 0x0000000103410b68
llvm::sys::PrintStackTrace(__sFILE*) + 40
1 Swift 4 0x0000000103411054 SignalHandler(int) + 452
2 libsystem_platform.dylib 0x00007fff9176af1a _sigtramp + 26
3 libsystem_platform.dylib 0x000000000000000b _sigtramp + 1854492939
4 libsystem_platform.dylib 0x00000001074a0214 _sigtramp + 1976783636
5 Swift 4 0x0000000102a85c39
llvm::JIT::runFunction(llvm::Function*, std::__1::vector > const&) + 329
6 Swift 4 0x0000000102d320b3
llvm::ExecutionEngine::runFunctionAsMain(llvm::Function*,
std::__1::vector<std::__1::basic_string, std::__1::allocator >,
std::__1::allocator<std::__1::basic_string, std::__1::allocator > > > const&,
char const* const*) + 1523
7 Swift 4 0x000000010296e6ba Swift 4::RunImmediately(Swift
4::CompilerInstance&, std::__1::vector<std::__1::basic_string,
std::__1::allocator >, std::__1::allocator<std::__1::basic_string,
std::__1::allocator > > > const&, Swift 4::IRGenOptions&, Swift 4::SILOptions
const&) + 1066
8 Swift 4 0x000000010275764b frontend_main(llvm::ArrayRef,
char const*, void*) + 5275
9 Swift 4 0x0000000102754a6d main + 1677
10 libdyld.dylib 0x00007fff8bb9e5c9 start + 1
11 libdyld.dylib 0x000000000000000c start + 1950751300
Stack dump:
0. Program arguments:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/
usr/bin/Swift 4 -frontend -interpret - -target x86_64-apple-darwin14.0.0 -
target-cpu core2 -sdk
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/
SDKs/MacOSX10.10.sdk -module-name main
/bin/sh: line 47: 15672 Done cat <<'SWIFT 4'
import Foundation
</std::__1::basic_string</std::__1::basic_string</std::__1::basic_string</std::
__1::basic_string
Il programma precedente dichiara "sondaggio elettorale" come nome della classe e contiene "candidato" come funzione di appartenenza. La sottoclasse viene dichiarata come "poll booth" e "nome" come funzione di appartenenza che viene inizializzata come "MP". La chiamata alla super classe viene inizializzata creando un'istanza "cand" con opzionale "!". Poiché i valori non sono dichiarati nella sua classe base, il valore "nil" viene memorizzato restituendo un errore fatale dalla procedura di decompressione forzata.
Programma per concatenamento opzionale con "?"
class ElectionPoll {
var candidate: Pollbooth?
}
class Pollbooth {
var name = "MP"
}
let cand = ElectionPoll()
if let candname = cand.candidate?.name {
print("Candidate name is \(candname)")
} else {
print("Candidate name cannot be retreived")
}
Quando eseguiamo il programma precedente usando playground, otteniamo il seguente risultato:
Candidate name cannot be retreived
Il programma precedente dichiara "sondaggio elettorale" come nome della classe e contiene "candidato" come funzione di appartenenza. La sottoclasse viene dichiarata come "poll booth" e "nome" come funzione di appartenenza che viene inizializzata come "MP". La chiamata alla super classe viene inizializzata creando un'istanza "cand" con opzionale "?". Poiché i valori non sono dichiarati nella sua classe base, il valore 'nil' viene memorizzato e stampato nella console dal blocco del gestore else.
Definizione di classi di modelli per concatenamento e accesso alle proprietà facoltativi
Il linguaggio Swift 4 fornisce anche il concetto di concatenamento opzionale, per dichiarare più di una sottoclassi come classi modello. Questo concetto sarà molto utile per definire modelli complessi e per accedere alle proprietà, ai metodi e alle proprietà secondarie dei pedici.
class rectangle {
var print: circle?
}
class circle {
var area = [radius]()
var cprint: Int {
return area.count
}
subscript(i: Int) -> radius {
get {
return area[i]
}
set {
area[i] = newValue
}
}
func circleprint() {
print("The number of rooms is \(cprint)")
}
var rectarea: circumference?
}
class radius {
let radiusname: String
init(radiusname: String) { self.radiusname = radiusname }
}
class circumference {
var circumName: String?
var circumNumber: String?
var street: String?
func buildingIdentifier() -> String? {
if circumName != nil {
return circumName
} else if circumNumber != nil {
return circumNumber
} else {
return nil
}
}
}
let rectname = rectangle()
if let rectarea = rectname.print?.cprint {
print("Area of rectangle is \(rectarea)")
} else {
print("Rectangle Area is not specified")
}
Quando eseguiamo il programma precedente usando playground, otteniamo il seguente risultato:
Rectangle Area is not specified
Richiamo di metodi tramite concatenamento facoltativo
class rectangle {
var print: circle?
}
class circle {
var area = [radius]()
var cprint: Int {
return area.count
}
subscript(i: Int) -> radius {
get {
return area[i]
}
set {
area[i] = newValue
}
}
func circleprint() {
print("Area of Circle is: \(cprint)")
}
var rectarea: circumference?
}
class radius {
let radiusname: String
init(radiusname: String) { self.radiusname = radiusname }
}
class circumference {
var circumName: String?
var circumNumber: String?
var circumarea: String?
func buildingIdentifier() -> String? {
if circumName != nil {
return circumName
} else if circumNumber != nil {
return circumNumber
} else {
return nil
}
}
}
let circname = rectangle()
if circname.print?.circleprint() != nil {
print("Area of circle is specified)")
} else {
print("Area of circle is not specified")
}
Quando eseguiamo il programma precedente usando playground, otteniamo il seguente risultato:
Area of circle is not specified
La funzione circleprint () dichiarata all'interno della sottoclasse circle () viene chiamata creando un'istanza chiamata "circname". La funzione restituirà un valore se contiene un valore, altrimenti restituirà un messaggio di stampa definito dall'utente controllando l'istruzione 'if circname.print? .Circleprint ()! = Nil'.
Accesso agli indici tramite concatenamento facoltativo
Il concatenamento opzionale viene utilizzato per impostare e recuperare un valore di pedice per convalidare se la chiamata a tale pedice restituisce un valore. "?" viene posto prima delle parentesi graffe del pedice per accedere al valore facoltativo del particolare pedice.
Programma 1
class rectangle {
var print: circle?
}
class circle {
var area = [radius]()
var cprint: Int {
return area.count
}
subscript(i: Int) -> radius {
get {
return area[i]
}
set {
area[i] = newValue
}
}
func circleprint() {
print("The number of rooms is \(cprint)")
}
var rectarea: circumference?
}
class radius {
let radiusname: String
init(radiusname: String) { self.radiusname = radiusname }
}
class circumference {
var circumName: String?
var circumNumber: String?
var circumarea: String?
func buildingIdentifier() -> String? {
if circumName != nil {
return circumName
} else if circumNumber != nil {
return circumNumber
} else {
return nil
}
}
}
let circname = rectangle()
if let radiusName = circname.print?[0].radiusname {
print("The first room name is \(radiusName).")
} else {
print("Radius is not specified.")
}
Quando eseguiamo il programma precedente usando playground, otteniamo il seguente risultato:
Radius is not specified.
Nel programma precedente i valori di istanza per la funzione di appartenenza "radiusName" non sono specificati. Quindi la chiamata del programma alla funzione restituirà solo un'altra parte mentre per restituire i valori dobbiamo definire i valori per la particolare funzione di appartenenza.
Programma 2
class rectangle {
var print: circle?
}
class circle {
var area = [radius]()
var cprint: Int {
return area.count
}
subscript(i: Int) -> radius {
get {
return area[i]
}
set {
area[i] = newValue
}
}
func circleprint() {
print("The number of rooms is \(cprint)")
}
var rectarea: circumference?
}
class radius {
let radiusname: String
init(radiusname: String) { self.radiusname = radiusname }
}
class circumference {
var circumName: String?
var circumNumber: String?
var circumarea: String?
func buildingIdentifier() -> String? {
if circumName != nil {
return circumName
} else if circumNumber != nil {
return circumNumber
} else {
return nil
}
}
}
let circname = rectangle()
circname.print?[0] = radius(radiusname: "Diameter")
let printing = circle()
printing.area.append(radius(radiusname: "Units"))
printing.area.append(radius(radiusname: "Meter"))
circname.print = printing
if let radiusName = circname.print?[0].radiusname {
print("Radius is measured in \(radiusName).")
} else {
print("Radius is not specified.")
}
Quando eseguiamo il programma precedente usando playground, otteniamo il seguente risultato:
Radius is measured in Units.
Nel programma precedente, vengono specificati i valori di istanza per la funzione di appartenenza "radiusName". Quindi la chiamata del programma alla funzione ora restituirà valori.
Accesso a pedici di tipo facoltativo
class rectangle {
var print: circle?
}
class circle {
var area = [radius]()
var cprint: Int {
return area.count
}
subscript(i: Int) -> radius {
get {
return area[i]
}
set {
area[i] = newValue
}
}
func circleprint() {
print("The number of rooms is \(cprint)")
}
var rectarea: circumference?
}
class radius {
let radiusname: String
init(radiusname: String) { self.radiusname = radiusname }
}
class circumference {
var circumName: String?
var circumNumber: String?
var circumarea: String?
func buildingIdentifier() -> String? {
if circumName != nil {
return circumName
} else if circumNumber != nil {
return circumNumber
} else {
return nil
}
}
}
let circname = rectangle()
circname.print?[0] = radius(radiusname: "Diameter")
let printing = circle()
printing.area.append(radius(radiusname: "Units"))
printing.area.append(radius(radiusname: "Meter"))
circname.print = printing
var area = ["Radius": [35, 45, 78, 101], "Circle": [90, 45, 56]]
area["Radius"]?[1] = 78
area["Circle"]?[1]--
print(area["Radius"]?[0])
print(area["Radius"]?[1])
print(area["Radius"]?[2])
print(area["Radius"]?[3])
print(area["Circle"]?[0])
print(area["Circle"]?[1])
print(area["Circle"]?[2])
Quando eseguiamo il programma precedente usando playground, otteniamo il seguente risultato:
Optional(35)
Optional(78)
Optional(78)
Optional(101)
Optional(90)
Optional(44)
Optional(56)
È possibile accedere ai valori facoltativi per i pedici facendo riferimento ai loro valori in pedice. È possibile accedervi come pedice [0], pedice [1] ecc. I valori di pedice predefiniti per "raggio" vengono prima assegnati come [35, 45, 78, 101] e per "Cerchio" [90, 45, 56]] . Quindi i valori del pedice vengono modificati come Raggio [0] in 78 e Cerchio [1] in 45.
Collegamento di più livelli di concatenamento
È inoltre possibile collegare più sottoclassi con i suoi metodi, proprietà e pedici di super classe mediante concatenamento opzionale.
È possibile collegare più concatenamenti di optional -
Se il recupero del tipo non è facoltativo, il concatenamento facoltativo restituirà un valore facoltativo. Ad esempio, se String attraverso il concatenamento opzionale restituirà String? Valore
class rectangle {
var print: circle?
}
class circle {
var area = [radius]()
var cprint: Int {
return area.count
}
subscript(i: Int) -> radius {
get {
return area[i]
}
set {
area[i] = newValue
}
}
func circleprint() {
print("The number of rooms is \(cprint)")
}
var rectarea: circumference?
}
class radius {
let radiusname: String
init(radiusname: String) { self.radiusname = radiusname }
}
class circumference {
var circumName: String?
var circumNumber: String?
var circumarea: String?
func buildingIdentifier() -> String? {
if circumName != nil {
return circumName
} else if circumNumber != nil {
return circumNumber
} else {
return nil
}
}
}
let circname = rectangle()
if let radiusName = circname.print?[0].radiusname {
print("The first room name is \(radiusName).")
} else {
print("Radius is not specified.")
}
Quando eseguiamo il programma precedente usando playground, otteniamo il seguente risultato:
Radius is not specified.
Nel programma precedente, i valori di istanza per la funzione di appartenenza "radiusName" non sono specificati. Quindi, la chiamata del programma alla funzione restituirà solo un'altra parte mentre per restituire i valori dobbiamo definire i valori per la particolare funzione di appartenenza.
Se il tipo di recupero è già facoltativo, anche il concatenamento facoltativo restituirà un valore facoltativo. Ad esempio se String? Si accede tramite concatenamento facoltativo restituirà String? Valore..
class rectangle {
var print: circle?
}
class circle {
var area = [radius]()
var cprint: Int {
return area.count
}
subscript(i: Int) -> radius {
get {
return area[i]
}
set {
area[i] = newValue
}
}
func circleprint() {
print("The number of rooms is \(cprint)")
}
var rectarea: circumference?
}
class radius {
let radiusname: String
init(radiusname: String) { self.radiusname = radiusname }
}
class circumference {
var circumName: String?
var circumNumber: String?
var circumarea: String?
func buildingIdentifier() -> String? {
if circumName != nil {
return circumName
} else if circumNumber != nil {
return circumNumber
} else {
return nil
}
}
}
let circname = rectangle()
circname.print?[0] = radius(radiusname: "Diameter")
let printing = circle()
printing.area.append(radius(radiusname: "Units"))
printing.area.append(radius(radiusname: "Meter"))
circname.print = printing
if let radiusName = circname.print?[0].radiusname {
print("Radius is measured in \(radiusName).")
} else {
print("Radius is not specified.")
}
Quando eseguiamo il programma precedente usando playground, otteniamo il seguente risultato:
Radius is measured in Units.
Nel programma precedente, vengono specificati i valori di istanza per la funzione di appartenenza "radiusName". Quindi, la chiamata del programma alla funzione ora restituirà valori.
Concatenamento di metodi con valori di ritorno opzionali
Il concatenamento opzionale viene utilizzato anche per accedere ai metodi definiti delle sottoclassi.
class rectangle {
var print: circle?
}
class circle {
var area = [radius]()
var cprint: Int {
return area.count
}
subscript(i: Int) -> radius {
get {
return area[i]
}
set {
area[i] = newValue
}
}
func circleprint() {
print("Area of Circle is: \(cprint)")
}
var rectarea: circumference?
}
class radius {
let radiusname: String
init(radiusname: String) { self.radiusname = radiusname }
}
class circumference {
var circumName: String?
var circumNumber: String?
var circumarea: String?
func buildingIdentifier() -> String? {
if circumName != nil {
return circumName
} else if circumNumber != nil {
return circumNumber
} else {
return nil
}
}
}
let circname = rectangle()
if circname.print?.circleprint() != nil {
print("Area of circle is specified)")
} else {
print("Area of circle is not specified")
}
Quando eseguiamo il programma precedente usando playground, otteniamo il seguente risultato:
Area of circle is not specified