Могу ли я указать, что универсальный тип является типом значения?

Я знаю, что мы можем указать, что наши дженерики должны быть любым ссылочным типом, используя AnyObject:

class Foo<T: AnyObject> {
    // ...
}

Но есть ли способ указать, что наши дженерики должны быть только типами value и не разрешать ссылочные типы?


person nhgrif    schedule 28.02.2015    source источник
comment
Я подозреваю, что лучший способ справиться с этим будет внутри самого метода. То, как работают дженерики, затруднит предлагаемую функциональность, и я не знаю ни одного языка, который это позволяет.   -  person Tim    schedule 28.02.2015
comment
Хотя я не верю, что вы можете сделать это общим способом во время компиляции, вы должны хотя бы взглянуть на isUniquelyReferenced(), чтобы увидеть, можете ли вы получить утверждения во время выполнения вашей основной цели (что, как я предполагаю, является уверенностью в том, что объект не может измениться после вашего назад). Я бы обязательно поднял ваш вариант использования на форумах разработчиков (devforums.apple.com/community/tools /languages/swift). Это очень интересный вопрос.   -  person Rob Napier    schedule 28.02.2015
comment
Написанная Apple литература по Swift чрезвычайно откровенна в этом отношении, и ваша семантика неконструктивна, @newacct   -  person nhgrif    schedule 12.01.2016
comment
@nhgrif: тип значения и ссылочный тип - это неформальные понятия, которые удобно описывать в некоторой литературе для упрощенных образовательных целей. На самом деле четкого разграничения нет. Я знаю, что под типом значения вы имеете в виду только структуры и перечисления. Но напр. UnsafeMutablePointer — это тип структуры, на которую можно изменять состояние, на которое она указывает, не изменяя саму структуру. Разве это не ссылочный тип? Поведение ссылочного типа может быть встроено в типы структур, поэтому вы ничего не избегаете, исключая ссылочные типы.   -  person newacct    schedule 12.01.2016
comment
@newacct «Тип значения» и «ссылочный тип» являются формальными понятиями, которые имеют четкие различия в том, как они обрабатываются компилятором, хранятся в памяти и используются переменными, когда вы язык специально проводит четкое различие между ними, что делает Swift. Мы все понимаем, что эти термины также являются общими терминами программирования, которые могут означать разные вещи на разных языках. Однако в таких языках, как C, Objective-C и Swift, они имеют четкую, отличительную семантику.   -  person Slipp D. Thompson    schedule 23.02.2017
comment
@newacct Я рекомендую вам прочитать язык программирования Swift от Apple. - Глава "Классы и структуры" перед дальнейшим объединением концепций CS с конструкциями Swift. Сразу после начальных 4 предложений этой главы находится пара хороших маркированных списков, четко определяющих все сходства и различия между Swift classes и structs, а далее вы найдете Структуры и перечисления являются типами значений и Классы являются ссылочными типами.   -  person Slipp D. Thompson    schedule 23.02.2017
comment
@newacct Чтобы ответить на ваш вопрос в стиле адвоката дьявола, нет, UnsafeMutablePointer не является ссылочным типом — это тип значения, который имеет адрес памяти в качестве своих данных. Этот адрес памяти может использоваться в качестве ссылки в специальном режиме, но экземпляр UnsafeMutablePointer остается типом значения. Самое главное, что использование ad-hoc не является обычным «родным» способом использования Swift — UnsafeMutablePointer предоставляется в первую очередь в качестве моста для возможности использования C API, и поэтому Swift должен иметь стороннюю поддержку для всех сумасшествие C-указателя, которое может сделать C.   -  person Slipp D. Thompson    schedule 23.02.2017
comment
когда ваш язык специально проводит четкое различие между ними, что делает Swift. И какое различие существует на семантическом уровне?   -  person newacct    schedule 24.02.2017
comment
@newacct Я рекомендую вам опубликовать новый вопрос, задающий именно это. StackOverflow — это сайт вопросов и ответов, а не форум.   -  person nhgrif    schedule 24.02.2017
comment
@nhgrif: я не задаю вопрос. Я категорически утверждаю, что на уровне языковой семантики нет различия.   -  person newacct    schedule 24.02.2017


Ответы (1)


// some code for testing    
class C { } // just a simple class as an example for a reference type
var c = C()
var d: Double = 0.9 // a value type

Решение 1 через extension

protocol ValueType { }
extension Double : ValueType { }
extension Int : ValueType { }
// ... all value types to be added

func printT1 <T: ValueType> (input: T) {
    println("\(input) is value")
}
printT1(d) // Does work
//printT1(c) // Does not work

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


Решение 2 через подпись метода

func printT <T: AnyObject> (input: T) {
    println("\(input) is reference")
}

func printT <T: Any> (input: T) {
    println("\(input) is value")
}

Решение 3 через assert

Другое решение может быть через assert

func printT <T: Any> (input: T) {
    print("\(input) is " + ((T.self is AnyObject) ? "reference" : "value"))
}

«Решение» 4 через пункты where

Это будет лучшим решением, я думаю. К сожалению, нет возможности иметь

func printT <T: Any where T: ~AnyObject > (input: T) {
    println("\(input) is value")
}

или похожие. Возможно, это будет возможно в будущих версиях Swift.

person Michael Dorner    schedule 28.02.2015
comment
протокол Equatable предназначен для типов значений, тогда как протокол Comparable предназначен для ссылочных типов - я так не думаю. Equatable означает, что вы можете проверить равенство с помощью ==, а Comparable означает, что, кроме того, существует строгий порядок с <. Это не связано со значениями и ссылочными типами. (Например, NSObject является ссылочным типом и соответствует Equatable.) - person Martin R; 28.02.2015
comment
Как можно написать протокол, который могут подтвердить только типы значений? Мы вернулись к тому же вопросу... - person nhgrif; 28.02.2015
comment
Кроме того, я не могу сразу понять, как заставить where работать для этого, и я не уверен, почему вы упомянули об этом, не включив пример. - person nhgrif; 01.03.2015
comment
И, наконец, пользовательский протокол технически будет работать... но он кажется довольно хакерским и сопряжен с двумя основными недостатками: созданные пользователем enum и struct не соответствуют ему автоматически (их нужно добавить... что в значительной степени означает, что я действительно не могу распространять в библиотеке этот код). Более того, ничто не мешает созданным пользователями классам соответствовать протоколу и затем использоваться. - person nhgrif; 01.03.2015
comment
Да. Вы правы, но это были мои первые идеи, может кто-то захочет улучшить наши аугменты. - person Michael Dorner; 01.03.2015
comment
Есть идеи по поводу проверки реализации оператора ===? - person Michael Dorner; 01.03.2015
comment
=== определен для AnyObject, поэтому, по-видимому, все, что не может его использовать, является типом значения. Определить, можно ли что-то использовать с ===, похоже, то же самое, что определить, является ли это AnyObject. Я не уверен, что это более полезно, чем тот факт, что мы можем использовать AnyObject, чтобы узнать, что это ссылочный тип. - person nhgrif; 01.03.2015
comment
Давайте продолжим обсуждение в чате. - person Michael Dorner; 01.03.2015