新的SwiftUI教程有以下代码:

struct ContentView: View {
    var body: some View {
        Text("Hello World")
    }
}

第二行是单词some,在他们的网站上突出显示,就好像它是一个关键字一样。

Swift 5.1似乎没有把some作为关键字,而且我不知道some这个词还能在那里做什么,因为它在类型通常的位置。有没有一个新的、未公布的Swift版本?它是一个我不知道的被用在类型上的函数吗?

关键字有的作用是什么?


当前回答

你可以假设swift是通用的。

其他回答

简单的理解方法,比如Objc中的kindOf

在我的理解中(可能是错误的)

这是我拥有的

Protocol View{}

 class Button: View { // subclass of View } 

 //this class not a subclass of View
 class ButtonBuilder<T> where T:View { //using T as View here   } 

Then

var body: View = Button() // ok
var body: View = ButtonBilder() //not ok
var body: some View = ButtonBilder() //ok

So

一些协议

使用该协议的泛型类是否可以在自己的代码中作为协议的子类处理

我将尝试用非常基本的实际示例回答这个问题(这是一个关于什么的不透明结果类型)

假设你有关联类型的协议,并且有两个结构实现它:

protocol ProtocolWithAssociatedType {
    associatedtype SomeType
}

struct First: ProtocolWithAssociatedType {
    typealias SomeType = Int
}

struct Second: ProtocolWithAssociatedType {
    typealias SomeType = String
}

在Swift 5.1之前,下面是非法的,因为ProtocolWithAssociatedType只能用作泛型约束错误:

func create() -> ProtocolWithAssociatedType {
    return First()
}

但在Swift 5.1中,这是可以接受的(一些人补充说):

func create() -> some ProtocolWithAssociatedType {
    return First()
}

以上是实际使用,广泛用于SwiftUI的一些视图。

但有一个重要的限制-返回类型需要在编译时知道,所以下面的函数声明了一个不透明的返回类型,但其主体中的返回语句没有匹配的底层类型错误:

func create() -> some ProtocolWithAssociatedType {
    if (1...2).randomElement() == 1 {
        return First()
    } else {
        return Second()
    }
}

为了简化,如果你知道两者的区别

var x = 5

vs

int x =5

然后你就会知道一些。 编译器知道它,您也知道它。在不指定具体细节(它使用的泛型类型)的情况下,尽可能地说明您遵守了某些内容

另一个答案很好地解释了新some关键字的技术方面,但这个答案将试图简单地解释为什么。


假设我有一个协议动物,我想比较两个动物是否是兄弟姐妹:

protocol Animal {
    func isSibling(_ animal: Self) -> Bool
}

这样,如果两个动物是同一类型的动物,那么比较它们是否是兄弟姐妹才有意义。


现在我举一个动物的例子供大家参考

class Dog: Animal {
    func isSibling(_ animal: Dog) -> Bool {
        return true // doesn't really matter implementation of this
    }
}

没有T的方式

现在,假设我有一个函数,从一个“家族”中返回一个动物。

func animalFromAnimalFamily() -> Animal {
    return myDog // myDog is just some random variable of type `Dog`
}

注意:这个函数实际上不会编译。这是因为在添加'some'特性之前,如果协议使用'Self'或泛型,则不能返回协议类型。但是假设你可以…假设这将myDog向上转换为抽象类型Animal,让我们看看会发生什么

现在问题来了,如果我试着这么做:

let animal1: Animal = animalFromAnimalFamily()
let animal2: Animal = animalFromAnimalFamily()

animal1.isSibling(animal2) // error

这将抛出一个错误。

为什么?原因是,当你调用animal1.isSibling(animal2)时,Swift不知道这些动物是狗、猫还是什么。据斯威夫特所知,animal1和animal2可能是不相关的动物物种。因为我们不能比较不同类型的动物(见上文)。这会出错

某个T如何解决这个问题

让我们重写之前的函数:

func animalFromAnimalFamily() -> some Animal {
    return myDog
}
let animal1 = animalFromAnimalFamily()
let animal2 = animalFromAnimalFamily()

animal1.isSibling(animal2)

animal1和animal2不是Animal,但它们是实现Animal的类。

这让你现在做的是,当你调用animal1. issibling (animal2)时,Swift知道animal1和animal2是同一类型。

所以我喜欢这样思考:

一些T让Swift知道T的什么实现正在被使用,但类的用户不知道。

(自我推销免责声明)我已经写了一篇博客文章,更深入地讨论了这个新功能(例子和这里一样)