Значимые и ссылочные типы

Последнее обновление: 02.01.2018

Для создания объектов мы можем выбрать либо классы, либо структуры, либо в отдельных случаях перечисления.

Классы и структуры имеют ряд общих черт:

  • В них можно определить свойства для хранения значений

  • В них можно определить методы, которые выполняют некоторую программную логику

  • И классы, и структуры поддерживают сабскрипты и инициализаторы

Однако классы имеют дополнительные возможности, которых нет у структур:

  • С помощью механизма наследования можно наследовать один класс от другого

  • Преобразование типов позволяет проверить и должным образом интерпретировать тип класса во время выполнения программы

  • Деинициализаторы позволяют освободить все связанные с объектом класса ресурсы

  • На один и тот же объект класса могут ссылаться сразу несколько переменных

Но главное отличие классов от структур заключается в том, что классы представляют ссылочные типы (reference types), а структуры, а также перечисления - значимые типы или типы значений (value types). Это накладывает отпечаток на использование этих типов в различных ситуациях. Рассмотрим некоторые из них.

Изменение константы

При определении объекта с помощью ключевого слова let он ставится константой. Однако объекты классов и структур ведут себя по разному:

class Person{
    
    var name: String
    var age: Int
    init(name: String, age: Int){
        
        self.name = name
        self.age = age
    }
}
struct User{
    
    var name: String
    var age: Int
}

let tom: Person = Person(name: "Tom", age: 24)
let bob: User = User(name:"Bob", age: 24)
tom.age = 25        // норм
bob.age = 25        // ошибка

Здесь определены практически идентичные типы: Person и User. Только один представляет класс, а другой структуру. Константым объектам нельзя присвоить новое значение. Однако если константый объект представляет класс, то мы можем изменить значения его отдельных свойств. Со структурой это не работает, потому что при изменении свойства структуры Swift полностью меняет объект этой структуры, что для константных объектов недопустимо.

Копирование значений

При передаче значения переменной или константы значимого типа в другую переменную или константу происходит копирование этого значения, а при передаче значения ссылочного типа передается ссылка на область в памяти, в которой хранится это значение.

Вначале рассмотрим ситуацию с классами:

class Person{
	
	var name: String
	var age: Int
	init(name: String, age: Int){
		
		self.name = name
		self.age = age
	}
}

var tom: Person = Person(name: "Tom", age: 24)
var bob = tom
bob.name = "Bob"
print(tom.name)	// Bob

Здесь определяется переменная tom, которая представляет класс Person. После ее присвоения переменной bob обе этих переменных будут указывать на один и тот же объект в памяти. То есть присвоение фактически приведет к копированию ссылки на объект памяти. Поэтому при изменении свойств в переменной tom, также изменятся значения свойств в переменной bob. Так как это свойства одного и того же объекта в памяти.

struct User{
	
	var name: String
	var age: Int
}

var alice: User = User(name: "Alice", age: 24)
var bil = alice
bil.name = "Bil"
print(alice.name)	// Alice

Здесь определяется похожая структура User. Далее создаем объект этой структуры alice. Затем присваиваем этот объект переменной bil. В результате присвоения произойдет копирование значений объекта alice в объект bil. Поэтому если мы изменим свойства переменной bil, то свойства переменной alice не изменят своих значений. Так как это два разных объекта в памяти.

Оператор идентичности

В связи с тем, что классы представляют ссылочные типы, для сравнения экземпляров класса используется оператор идентичности - ===:

class Person{
	
	var name: String
	var age: Int
	init(name: String, age: Int){
		
		self.name = name
		self.age = age
	}
}

var tom: Person = Person(name: "Tom", age: 24)
var bob = tom
var anotherTom: Person = Person(name: "Tom", age: 24)

bob === tom		// true - ссылка на один и тот же объект
anotherTom === tom	// false - ссылка на разные объекты

Так как переменные bob и tom хранят ссылку на один и тот же объект в памяти, то оператор идентичности возвратит значение true.

Зато переменная anotherTom хранит ссылку на другой объект в памяти, не смотря на то, что ее свойства хранят те же значения, что и свойства в переменной tom. Но поскольку ссылки разные, то оператор идентичности возвратит значение false.

В противоположность оператору идентичности, который возвращает true в случае равенства ссылок, в Swift также есть оператор !==, который возвращает true если ссылки не равны:

anotherTom !== tom	// true
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850