如何在 Swift 中使用名称空间?

文档只提到了嵌套类型,但不清楚它们是否可以用作名称空间。我没有发现任何关于名称空间的明确提及。

79515 次浏览

我相信这是通过以下方法实现的:

struct Foo
{
class Bar
{
}
}

然后可以通过以下方式访问:

var dds = Foo.Bar();

Swift 使用的模块非常类似于 python (参见 给你给你) ,@Kevin Sylvestre 建议您也可以使用 嵌套类型作为名称空间。

为了扩展@Daniel A. White 的回答,在 WWDC 他们正在迅速讨论模块。

还解释了 给你:

推断类型使代码更清晰,更不容易出错,而 模块消除标头并提供名称空间。

711苹果开发论坛中回答:

命名空间不是针对每个文件; 而是针对每个目标(基于 “ Product Module Name”构建设置) 像这样:

import FrameworkA
import FrameworkB


FrameworkA.foo()

所有 Swift 声明都被认为是 一些模块,所以即使你说“ NSLog”(是的,它仍然存在) 你得到了斯威夫特眼中的“ Foundation.NSLog”。

还有 Chris Lattner 关于名称空间的推特

名称间距在 Swift 中是隐式的,所有类(等)都是隐式的 它们所在的模块(Xcode 目标)的范围。没有类前缀 需要

看起来和我想的很不一样。

在做这方面的实验时,我最终通过扩展根“包”在他们自己的文件中创建了这些“名称空间”类。不确定这是否违背了最佳实践,或者是否有我不知道的暗示(?)

应用代理,迅捷

var n1 = PackageOne.Class(name: "Package 1 class")
var n2 = PackageTwo.Class(name: "Package 2 class")


println("Name 1: \(n1.name)")
println("Name 2: \(n2.name)")

包裹一,迅捷

import Foundation


struct PackageOne {
}

第二包,迅捷

import Foundation


struct PackageTwo {
}

包裹一级,迅捷

extension PackageOne {
class Class {
var name: String
init(name:String) {
self.name = name
}
}
}

包裹 TwoClass.swift

extension PackageTwo {
class Class {
var name: String
init(name:String) {
self.name = name
}
}
}

编辑:

刚刚发现,如果使用单独的文件,在上面的代码中创建“子包”是行不通的。也许有人能提示一下为什么会这样?

向上面添加以下文件:

包裹一,小包裹,迅速

import Foundation


extension PackageOne {
struct SubPackage {
}
}

类别: 迅速

extension PackageOne.SubPackage {
class Class {
var name: String
init(name:String) {
self.name = name
}
}
}

它抛出了一个编译器错误: ‘ SubPackage’不是‘ PackageOne’的成员类型

如果我将代码从 PackageOneSubPackageClass.swift 移动到 PackageOneSubPackage.swift,它就可以工作了,有人知道吗?

编辑2:

在 Xcode 6.1 beta 2中,我们发现通过在一个文件中定义包,它们可以在不同的文件中进行扩展:

public struct Package {
public struct SubPackage {
public struct SubPackageOne {
}
public struct SubPackageTwo {
}
}
}

以下是我的文件大意: Https://gist.github.com/mikajauhonen/d4b3e517122ad6a132b8

如果有人好奇的话,在2014年6月10日,这是一个已知的错误在 Swift:

来自 711

“已知错误,对不起! Rdar://problem/17127940通过模块名称限定 Swift 类型不起作用。”

我认为斯威夫特的名称空间是有抱负的; 它得到了大量的广告,但这些广告并不符合任何有意义的现实。

例如,WWDC 视频声明,如果您导入的框架有一个类 MyClass,而您的代码有一个类 MyClass,那么这些名称不会冲突,因为“名称错位”给了它们不同的内部名称。然而,在现实中,它们与 冲突,在这个意义上,你自己的代码的 MyClass 获胜,你不能指定“不,不,我的意思是框架中的 MyClass”ーー说 TheFramework.MyClass不工作(编译器知道你的意思,但它说它不能在框架中找到这样的类)。

我的经验是,Swift 因此根本没有名称空间。在将我的一个应用程序从 Objective-C 转换成 Swift 的过程中,我创建了一个嵌入式框架,因为它实在是太简单太酷了。然而,导入框架会导入框架中的所有 Swift 内容——所以很快,又只有一个名称空间,而且是全局的。而且没有 Swift 头,所以你不能隐藏任何名字。

编辑: 在种子3中,这个特性现在开始上线了,在以下意义上: 如果你的主代码包含 MyClass,而你的框架 MyFramework 包含 MyClass,默认情况下,前者会盖过后者,但是你可以通过使用语法 MyFramework.MyClass来到达框架中的那个。因此,我们实际上已经具备了一个独特名称空间的基本知识!

编辑2: 在种子4中,我们现在有了访问控制!另外,在我的一个应用程序中,我有一个嵌入式框架,毫无疑问,默认情况下,所有东西都是隐藏的,我必须显式地公开所有的公共 API。这是一个很大的进步。

您可以使用 extension来使用上面提到的 structs 方法来实现名称空间,而不必将所有代码向右缩进。我一直在玩这个,我不确定我会像下面的例子那样创建 ControllersViews名称空间,但它确实说明了它能走多远:

配置文件迅速 :

// Define the namespaces
struct Profiles {
struct Views {}
struct ViewControllers {}
}

Profiles/ViewController/Edit.swift

// Define your new class within its namespace
extension Profiles.ViewControllers {
class Edit: UIViewController {}
}


// Extend your new class to avoid the extra whitespace on the left
extension Profiles.ViewControllers.Edit {
override func viewDidLoad() {
// Do some stuff
}
}

配置文件/视图/编辑

extension Profiles.Views {
class Edit: UIView {}
}


extension Profiles.Views.Edit {
override func drawRect(rect: CGRect) {
// Do some stuff
}
}

我还没有在应用程序中使用这个,因为我还没有需要这种程度的分离,但我认为这是一个有趣的想法。这就消除了对类后缀的需求,比如无处不在的 * ViewController 后缀,这个后缀非常长。

但是,当引用它时,它不会缩短任何内容,比如在方法参数中,如下所示:

class MyClass {
func doSomethingWith(viewController: Profiles.ViewControllers.Edit) {
// secret sauce
}
}
  • 当需要在现有框架中定义类名为 一样的类时,名称空间非常有用。

  • 假设您的应用程序具有 MyApp名称,并且您需要声明您的自定义 UICollectionViewController

你的 不需要前缀和子类如下:

class MAUICollectionViewController: UICollectionViewController {}

这样做:

class UICollectionViewController {} //no error "invalid redeclaration o..."

为什么?.因为你所声明的是在 电流模组中声明的,也就是你的 目前的目标。来自 UIKitUICollectionViewControllerUIKit模块中声明。

如何在当前模块中使用它?

var customController = UICollectionViewController() //your custom class
var uikitController = UIKit.UICollectionViewController() //class from UIKit

如何将它们与其他模块区分开来?

var customController = MyApp.UICollectionViewController() //your custom class
var uikitController = UIKit.UICollectionViewController() //class from UIKit

尽管可以使用框架和库来实现名称空间,但是最好的解决方案是使用 Swift Package Manager 来使用本地包。除了具有访问修饰符之外,这种方法还有其他一些好处。正如在 Swift Package Manager 中一样,文件是基于目录系统管理的,而不是它们的目标成员,因此您不必为团队合并中经常出现的冲突而苦恼。此外,不需要设置文件成员身份。

如欲了解如何使用本地 Swift 软件包,请参考以下连结: 使用本地包组织代码