The Swift Programming Language-class and struct, swift struct
Classes and struct in Swift have many things in common. The common cause is:
• Define attributes for storing values
• Define methods to provide functions
• Defining subscript is used to access values through subscript syntax
• Defines the initialization tool used to generate the initialization value
• Added functions implemented by default through extension
• Complies with the protocol to provide standard functions for a certain type of Feature
For more information, see attributes, methods, subscripts, initial processes, extensions, and protocols.
Compared with struct, classes have the following additional functions:
• Inheritance allows one class to inherit the features of another class
• Type conversion allows you to check and interpret the type of a class instance at runtime
• The uninitialized device allows a class instance to release any resources it is allocated.
• Reference count allows multiple references to a class
For more information, see inheritance, type conversion, initialization, and automatic reference count.
Note:
The struct is always transmitted in the Code by copying it. Therefore, do not use reference count.
Definition
Classes and struct have similar definitions. We use the keywords class and struct to represent classes and struct respectively, and define their specific content in a pair of braces:
class SomeClass { // class definition goes here}struct SomeStructure { // structure definition goes here}
Note:
Every time you define a new class or struct, you actually effectively define a new Swift type. Therefore, use UpperCamelCase (such as SomeClass and SomeStructure) to conform to the standard capital naming style of Swift (such as String, Int, and Bool ). Instead, use lowerCamelCase to name attributes and methods (such as framerate and incrementCount) to distinguish them from classes.
The following is an example of defining struct and definition classes:
struct Resolution { var width = 0 var heigth = 0}class VideoMode { var resolution = Resolution() var interlaced = false var frameRate = 0.0 var name: String?}
In the preceding example, we define a structure named Resolution to describe the pixel Resolution of a display. This struct contains two storage attributes named width and height. A storage attribute is a constant or variable bound to and stored in a class or struct. When these two attributes are initialized to an integer 0, they are inferred to be of the Int type.
In the above example, we also define a class named VideoMode to describe a specific mode of a video display. This class contains four storage attribute variables. The first is the Resolution. It is initialized as an instance of a new Resolution struct and has a Resolution attribute type. The new VideoMode instance also initializes the other three attributes, which are the intereceived whose initial value is false (meaning "non-interlaced video, the frameRate value of the initial playback frame rate of 0.0 and the value of the optional String name. The name attribute is automatically assigned a default value nil, indicating "NO name value" because it is an optional type.
Class and struct instance
The definition of the Resolution struct and VideoMode class only describes what is Resolution and VideoMode. They do not describe a specific resolution or video mode ). To describe a specific resolution or video mode, we need to generate an instance of them.
The syntax for generating struct and class instances is very similar:
let someResolution = Resolution()let someVideoMode = VideoMode()
Both struct and class use the initializer syntax to generate new instances. The simplest form of the initialization syntax is to follow an empty arc after the type name of the struct or class, such as Resolution () or VideoMode (). The class or struct instance created in this way will be initialized to the default value. The constructor chapter will discuss the initialization of classes and struct in more detail.
Attribute access
By using dot syntax, you can access the properties contained in the instance. The syntax rule is that the Instance name is followed by the attribute name, and the two are connected by the dot:
Println ("The width of someResolutionis \ (someResolution. width)") // output "The width ofsomeResolution is 0"
In the preceding example, someResolution. width references the width attribute of someResolution and returns the initial value of width 0.
You can also access the width attribute of the Resolution attribute in VideoMode:
Println ("The width of someVideoMode is \ (someVideoMode. resolution. width)") // output "The width ofsomeVideoMode is 0"
You can also use the dot syntax to assign values to attribute variables:
SomeVideoMode. resolution. width = 12880 println ("The width of someVideoMode isnow \ (someVideoMode. resolution. width)") // output "The width ofsomeVideoMode is now 1280"
Note:
Unlike the Objective-C language, Swift allows you to directly set sub-attributes of struct attributes. In the last example, the sub-attribute width of the resolution attribute in someVideoMode is directly set. The preceding operation does not need to set the resolution attribute.
Initialize the object type one by one.
//Memberwise Initializers for structureTypes
All Schemas have an automatically generated member initialize one by one, which is used to initialize the attributes of members in the new struct instance. The initial values of each attribute in the new instance can be passed to the members one by one through the attribute name:
Unlike struct, the class instance does not have default members to initialize one by one. The constructor will be discussed in more detail in the constructor.
Struct and enumeration are value types
The value type is assigned to a variable. When a constant or itself is passed to a function, the actual operation is its copy.
In the previous sections, we have used a large number of value types. In fact, in Swift, all basic types include Integer, floating-point, Boolean, string, and array) and Dictionary (dictionaries) are both value types and are implemented in the background in the form of struct.
In Swift, all struct and enumeration are value types. This means that their instances and any value type attributes contained in the instances will be copied when passed in the code.
See the following example, which uses the Resolution struct in the previous example:
let hd = Resolution(width: 1920, height:1080)var cinema = hd
In the preceding example, a constant named hd is declared, and its value is a Resolution instance initialized to the Full hd video Resolution (1920 pixels wide, 1080 pixels high.
In the example, a variable named cinema is declared and its value is the previously declared hd. Because Resolution is a struct, the value of cinema is actually a copy of hd instead of hd itself. Although hd and cinema share the same width and height attributes, they are two completely different instances in the background.
In order to meet the requirements of digital cinema screening (2048 pixels wide, 1080 pixels high), the width attribute of cinema needs to be modified as follows:
cinema.width = 2048
Here, the width attribute of cinema is changed to 2048:
Println ("cinema is now \ (cinema. width) pixels wide") // output "cinema isnow 2048 pixels wide"
However, the width attribute in the initial hd instance is still 1920:
Println ("hd is still \ (hd. width) pixels wide") // output "hd is still1920 pixels wide"
When assigning hd to cinema, the stored value (values) in hd is actually copied, And the copied data is stored in the new cinema instance. The result is that two completely independent instances happen to contain the same value. Since the two are independent of each other, changing the width of cinema to 2048 does not affect the width in hd ).
Enumeration also follows the same code of conduct:
Enum CompassPoint {case North, South, East, West} var currentDirection = CompassPoint. westlet rememberedDirection = currentDirectioncurrentDirection =. eastif rememberDirection =. west {println ("The remembered ction is still. west ")} // output" Theremembered direction is still. west"
In the preceding example, rememberedDirection is assigned the currentDirection value. In fact, it is assigned a copy of the value. Modifying the currentDirection value after the value assignment process does not affect the copy of the original value stored in rememberedDirection.
Class is a reference type
Unlike the value type, when a reference type is assigned to a variable, constant, or passed to a function, it is not copied. Therefore, an existing instance is referenced instead of its copy.
See the following example to use the previously defined VideoMode class:
let tenEighty = VideoMode()tenEighty.resolution = hdtenEighty.interlaced = truetenEighty.name = "1080i"tenEighty.frameRate = 25.0
In the preceding example, a constant named tenEighty is declared, which references a new instance of the VideoMode class. In the previous example, the video mode is assigned a copy (HD) of the hd resolution (1920*1080 ). Set it to interlaced and name it "1080i ". Finally, the frame rate is 25.0 frames per second.
Then, tenEighty is assigned a new Constant Value named alsoTenEighty, and the frame rate of alsoTenEighty is modified as follows:
let alsoTenEighty = tenEightyalsoTenEighty.frameRate = 30.0
Because the class is a reference type, tenEight and alsoTenEight actually reference the same VideoMode instance. In other words, they are just two names for the same instance.
Next, by viewing the frameRate attribute of tenEighty, we will find that it correctly displays the New Frame Rate of the basic VideoMode instance, with a value of 30.0:
Println ("The frameRate property oftenEighty is now \ (tenEighty. frameRate)") // output "TheframeRate property of theEighty is now 30.0"
Note that tenEighty and alsoTenEighty are declared as constants rather than variables. However, you can change tenEighty. frameRate and alsoTenEighty. frameRate because the two constants will not change themselves. They do not store the VideoMode instance, but only reference the VideoMode instance in the background. Therefore, the parameter frameRate of the referenced basic VideoMode is changed without changing the constant value.
Constant equal Operator
Because a class is a reference type, multiple constants and variables may reference a class instance at the same time in the background. (This is not true for struct and enumeration. Because they are value types, they are always copied when they are assigned to constants, variables, or passed to functions .)
It is helpful to determine whether two constants or variables reference the same class instance. To achieve this goal, Swift has two built-in constant operators:
Equivalent to (=)
It is not equivalent (! =)
Use these two operators to check whether two constants or variables reference the same instance:
If tenEighty = alsoTenTighty {println ("tenTighty and unable to the same Resolution instance.")} // output "tenEightyand alsoTenEighty refer to the same Resolution instance ."
Note the differences between "equivalent to" (represented by three equal signs, ===) and "equal" (represented by two equal signs, ===:
"Equivalent" indicates that constants or variables of two class types reference the same class instance.
"Equal" indicates that the values of the two instances are "equal" or "identical". The determination must follow the criteria defined by the class designer. Therefore, compared with "equal ", this is a more suitable method.
When you define your custom classes and struct, you are obligated to determine the criteria for determining that two instances are "equal. In the Operator Functions section, we will introduce in detail the process for implementing custom operators "equal to" and "not equal.
Pointer
If you have experience with C, C ++, or Objective-C, you may know that these languages use pointers to reference addresses in the memory. A Swift constant or variable references an instance of the reference type similar to a pointer in the C language. The difference is that it does not directly point to an address in the memory, and you do not need to use an asterisk (*) to indicate that you are creating a reference. In Swift, these references are defined in the same way as other constants or variables.
Class and struct Selection
In your code, you can use classes and struct to define your custom data types.
However, struct instances are always passed through values, and class instances are always passed through references. This means that the two apply to different tasks. When you are considering the data structures and functions of a project, you need to decide whether each data structure is defined as a class or a struct.
According to general rules, consider constructing struct when one or more of the following conditions are met:
Struct is mainly used to encapsulate a small amount of related simple data values.
It is expected that the encapsulated data will be copied rather than referenced when a struct instance is assigned or transferred.
Any value type attribute stored in the struct will also be copied rather than referenced.
Struct does not need to inherit another existing type attribute or behavior.
Appropriate struct candidates include:
The ry size encapsulates a width attribute and a height attribute, both of which are of the Double type.
A path within a certain range encapsulates a start attribute and a length attribute, both of which are of the Int type.
A point in the 3D Coordinate System encapsulates the x, y, and z attributes. The three attributes are of the Double type.
In all other cases, define a class, generate an instance of it, and manage and transmit it through reference. In practice, this means that most of the custom data structures should be classes rather than struct.
Assignment and copying of Collection types
Array and Dictionary types in Swift are implemented in the form of struct. However, when an array is assigned a constant or variable, or is passed to a function or method, its copy behavior is somewhat different from that of the dictionary and other struct.
The behavior descriptions of arrays and struct are essentially different from those of NSArray and NSDictionary. The latter is implemented in the form of classes, and the former is implemented in the form of struct. NSArray and NSDictionary instances are always assigned and transferred by referencing existing instances, rather than copying them.
Note:
The following describes the copying of arrays, dictionaries, strings, and other values. In your code, copying does seem to have been generated where there is a copy action. However, in the Swift background, only actual (actual) copies are executed if necessary. Swift manages all value copies to ensure optimal performance, so you do not need to avoid assigning values to ensure optimal performance. (The actual assignment is optimized by System Management)
Assignment and copying of dictionary types
Whenever a dictionary instance is assigned to a constant or variable, or passed to a function or method, the dictionary will be copied when a value is assigned or called. This process will be detailed in the section where struct and enumeration are value types.
If the keys (keys) AND/OR values (values) stored in the dictionary instance are of the value type (struct or enumeration), they will be copied when values are assigned or called. Conversely, if keys and/or values are of the reference type, the copied values will be references rather than the class instances or functions referenced by them. The copy behavior of the dictionary's key and value is the same as that of the attributes stored in the struct.
The following example defines a dictionary named ages, which stores the names and ages of four people. The ages dictionary is assigned a new variable named copiedAges, which is also copied during the assignment process. After the assignment is complete, ages and copiedAges are two independent dictionaries.
var ages = ["Peter": 23,"Wei": 35, "Anish": 65, "Katya": 19]var copiedAges = ages
The key (keys) of this dictionary is of the String type, and the value (values) is of the integer type. Both types are value types in Swift, so both types are copied when the dictionary is copied.
We can change the age value in a dictionary and check the corresponding value in another dictionary to prove that the ages dictionary is indeed copied. If you set the value of Peter to 24 in the copiedAges dictionary, the ages dictionary still returns the value 23 before the modification:
CopiedAges ["Peter"] = 24 println (ages ["Peter"]) // output "23"
Assignment and copying of Arrays
In Swift, the assignment and copy operations of the array (Arrays) type are much more complex than those of the Dictionary type. When operating on the Array content, the Array can provide performance close to the C language, and the copy behavior only occurs when necessary.
If you assign an Array instance to a variable or constant, or pass it as a parameter to a function or method call, the group content will not be copied when an event occurs. Instead, the array shares the same element sequence. When you modify an element in a group, the modification result is displayed in another array.
For an array, the copy operation only occurs when the operation may modify the array length. This behavior includes appending, inserting, removing, or ranged subscript to replace the elements in this range. Only when an array copy is required, the behavior rules of the array content are the same as those of the key value in the dictionary. For details, see [Assignment and copying of collection types] (# assignment_and_copy_behavior_for_collection_types.
The following example assigns an integer (Int) array to a variable named a, which is then assigned to the variables B and c:
var a = [1, 2, 3]var b = avar c = a
We can use subscript syntax on a, B, and c to get the first element of the array:
println(a[0])// 1println(b[0])// 1println(c[0])// 1
If you use the subscript syntax to modify the value of an element in the array, the corresponding values in a, B, and c will change. Note that when you use subscript syntax to modify a value, the copy operation does not occur, because the following table syntax does not change the array length when modifying the value:
a[0] = 42println(a[0])// 42println(b[0])// 42println(c[0])// 42
However, when you add a new element to a, the length of the array changes. When an element is appended, Swift creates a copy of the array. From then on, a will be an independent copy of the original array.
After the copy happens, if you modify the element value in a, a will return a different result from B and c, because the latter two reference the original array:
a.append(4)a[0] = 777println(a[0])// 777println(b[0])// 42println(c[0])// 42
Ensure the uniqueness of the array
Before operating on an array, or passing it to a function or a method call, it is necessary to determine that the array has a unique copy. The unshare method is called on the array variable to determine the uniqueness of the array reference. (When an array is assigned to a constant, the unshare method cannot be called)
If an array is referenced by multiple variables and the unshare method is called on one of the variables, the array will be copied. At this time, the variable will have its own independent array copy. When an array is referenced by only one variable, no copy is performed.
At the end of the previous example, both B and c reference the same array. At this time, calling the unshare Method on B will convert B into a unique copy:
b.unshare()
After the unshare method is called, modify the value of the first element in B. The three arrays (a, B, c) return three different values:
b[0] = -105println(a[0])// 77println(b[0])// -105println(c[0])// 42
Determine whether two arrays share the same element
Identity operators (= and! =) To determine whether two arrays or sub-arrays share the same bucket or element.
In the following example, the "constant to" Operator (=) is used to determine whether B and c share the same array element:
If B = c {println ("B and c still share the same array elements. ")} else {println (" B and c now refer to two independent sets of arrayelements. ")} // output" B and c nowrefer totwo independent sets of array elements."
In addition, we can use the constant operator to determine whether two sub-arrays share the same element. In the following example, we compare two equal sub-arrays of B and confirm that both sub-arrays reference the same element:
If B [0... 1] = B [0... 1] {println ("These two subarrays share the same elements. ")} else {println (" These two subarrays do not share the same elements. ")} // output" These twosubarrays share the same elements."
Force copy Array
We call the copy method of the array to perform forced explicit replication. This method performs shallow copy on the array and returns a new array containing the copy.
The following example defines a names array, which contains seven names. A copiedNames variable is also defined to store the results returned by calling the copy method on names:
var names = ["Mohsen","Hilary", "Justyn", "Amy", "Rich","Graham", "Vic"]var copiedNames = names.copy
We can modify an element in an array and check the corresponding elements in another array to determine that the names array has been copied. If you change the first element of copiedNames from "Mohsen" to "Mo", the returned result of the names array is still "Mohsen" before the copy occurs ":
CopiedName [0] = "Mo" println (name [0]) // output "Mohsen"
Note:
If you only need to ensure that your reference to the array is a unique reference, call the unshare method instead of the copy method. The unshare method creates an array copy only when necessary. The copy method creates a new copy at any time, even if the reference is already a unique reference.
Data Structure-structure definition confused
The above program has good compatibility and can be successfully compiled by the C compiler. The following program can only be compiled by the C ++ compiler. Because you have defined a struct tnode in C, but you must add struct when using it. For example, you need to declare a variable: struct tnode TreeNode. struct cannot be removed from C, but it can be removed in C ++. So for the convenience of calling, add typedef, you can directly use BT to declare the variable.