我可以指定一个泛型为值类型吗?

19

我知道我们可以使用 AnyObject 来指定泛型为任何引用类型:

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

但是有没有一种方法可以指定我们的泛型只应该是类型,不允许引用类型呢?


2
虽然我不认为你可以在编译时以通用的方式完成这个任务,但你至少应该查看 isUniquelyReferenced(),以查看是否可以获得对底层目标的运行时断言(我假设的是确保对象不能在背后更改)。我肯定会在 devforums 上提出你的用例(https://devforums.apple.com/community/tools/languages/swift)。这是一个非常有趣的问题。 - Rob Napier
@newacct “值类型”和“引用类型”是正式概念,它们在编译器处理、存储在内存中以及变量使用时有明显的区别,当你的语言特别强调这两者之间的区别时,Swift就是如此。我们都知道这些术语也是通用的编程术语,在不同的语言中可能有不同的含义。然而,在像C、Objective-C和Swift这样的语言中,它们具有硬性、独特的语义。 - Slipp D. Thompson
@newacct 我建议你在进一步混淆CS概念和Swift构造之前,阅读一下苹果的《The Swift Programming Language-Classes and Structures章节》。该章节开头的4个句子后面是一个很好的项目列表,清楚地定义了Swift中classstruct之间所有的相似之处和不同之处。在下方你还会找到“结构体和枚举是值类型(Value Types)”和“类是引用类型(Reference Types)”的部分。 - Slipp D. Thompson
1
@newacct 回答你的反对问题,UnsafeMutablePointer 不是一个引用类型 - 它是一个具有内存地址作为其数据的值类型。该内存地址可以以临时方式用作引用,但 UnsafeMutablePointer 的实例仍然是一个值类型。最重要的是,这种临时使用不是使用 Swift 的正常“本地”方式 - UnsafeMutablePointer 主要作为桥梁提供,以便能够使用 C API,因此 Swift 必须有对所有 C 指针疯狂行为的支持。 - Slipp D. Thompson
@nhgrif:我不是在问问题。我在明确地陈述,在语言语义层面上没有区别。 - newacct
显示剩余5条评论
1个回答

6
// 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

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")
}

通过 assert 实现的解决方案 3

另一个解决方案可以通过 assert 来实现。

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

使用where子句的“解决方案”4

我认为这是最好的解决方案。不幸的是,无法

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

或类似的方式。也许在未来的Swift版本中可能会实现。


5
"Equatable协议旨在用于值类型,而Comparable协议旨在用于引用类型" - 我不这么认为。Equatable表示您可以使用==检查“相等性”,而Comparable表示除此之外还有一个严格的顺序 <。这与值类型和引用类型无关。(例如,NSObject是一种引用类型并符合Equatable协议。) - Martin R
1
如何编写一个只有值类型可以遵循的协议?我们又回到了同样的问题... - nhgrif
此外,我无法立即看出如何使where子句对此起作用,并且我不确定为什么您提到它却没有包含示例。 - nhgrif
1
最后,自定义协议在技术上是可行的... 但感觉相当繁琐,并且有两个主要缺点:用户创建的enumstruct不会自动符合它(它们必须被添加... 这几乎意味着我无法将这段代码真正地分发到库中)。此外,没有任何阻止用户创建的类符合该协议并被使用的机制。 - nhgrif
===对于AnyObject进行了定义,因此可能无法使用它的任何内容都是值类型。确定某个内容是否可以使用===似乎与确定它是否为AnyObject相同。我不确定这比我们可以使用AnyObject来知道它是引用类型更有帮助。 - nhgrif
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接