【问题标题】:How to resolve conflict between struct and module names?如何解决结构和模块名称之间的冲突?
【发布时间】:2019-10-23 06:22:53
【问题描述】:

我有模块数据。内部数据我有 struct X。

struct X<T> {
   var t: T
}

类 Y 里面有 typealias X

class Y {
  typealias X = X<Int>
}

最后一个代码示例有编译错误:

类型别名“X”引用自身

好的,编译器无法理解 X 是在 Y 之外定义的结构,它认为这是 Y 中的类型别名。我试图通过添加容器模块名称来具体化 X。

class Y {
  typealias X = Data.X<Int>
}

但结果,编译器给出了其他错误:

“X”不是“数据”的成员类型

这怎么可能? X 是数据的成员。跳转到 Data 的定义后,我发现 Data 是 Foundation 中的结构体。

我无法删除 import Foundation,因为我的代码使用了 UUID 和日期。是否可以在不为 Data.X 创建不必要的类型别名的情况下解决此冲突?


(30.10.19) 在对当前问题有些困惑之后,我做了以下实验。我这样做是为了避免与标准 Swift 库有任何交叉。希望这篇笔记能更清楚地解决我的问题中描述的问题。

  • 使用 Src.swift 创建项目 A
public struct B {}
  • 使用 Src.swift 创建项目 B
public struct X { }
  • 使用 Src.swift 创建项目 C
import A
import B

struct X { }
typealias Y = B.X

编译 A、B、C 后,我有同样的错误(从语义的角度来看)。

“X”不是“B”的成员类型

【问题讨论】:

  • 您的模块名称完全错误。编译器如何区分你的模块和原生模块?
  • @Karman “怎么样?”这是关于政治的问题。作为替代方案,编译器可以给予模块名称比结构名称更高的优先级(即使它是本机的)。在这种政治中,我可以具体化 Foundation.Data。
  • 其实使用同名有很多问题。离开编译器,没有新开发者会知道这是模块Data 还是Fo​​undation Data。这是不现实的。命名约定不允许这样做。
  • @Kamran 这与命名约定无关,它与看起来像语义错误的编译错误有关。模块和类型不能在同一个上下文中使用,我无法想象新开发人员如何混淆模块和类型。但是编译器还不清楚,我正在寻找方法来清除它。
  • @Kamran 我检查了我可以很容易地解决结构的名称冲突。我在两者中都使用代码public class Data { } 创建了模块A 和B。我用代码print(A.Data.self); print(C.Data.self); print(Foundation.Data.self) 创建了模块C。所有模块都编译成功。对于编译器和新开发人员来说,正在使用哪些数据是很清楚的。我试图找到的解决方案对于新开发人员来说是显而易见的。但正如我所见,不存在任何解决方案。是真的吗?

标签: swift


【解决方案1】:

以下方案解决了包含 ABC 项目的第二种情况的结构和模块之间的名称冲突。此解决方案基于我们只能编辑 C 项目的规则。因为 C 是我们假设的第三方不可更改模块 AB 的客户。

  1. 将新的 Swift 文件添加到 C 项目中,代码如下
import struct A.B
typealias StructB = B
  1. 将 Src.swift 中的代码更改为以下内容
import B
let structB: StructB? = nil

struct X { }
typealias Y = B.X

结果是编译成功且没有错误:

“X”不是“B”的成员类型

我们可以在单个文件中使用模块 A 中的结构 B 和模块 B 中的结构。名称冲突已解决。


第二种情况解决了第一种情况与数据的冲突。

  1. 替换
import Foundation

import struct Foundation.Date
import struct Foundation.UUID
  1. 确保未在模块级别导入 Foundation。就我而言,我从 Data.h 中删除了 #import &lt;UIKit/UIKit.h&gt;。并将FOUNDATION_EXPORT 替换为extern 以使Data.h 可编译。

【讨论】:

    【解决方案2】:

    尝试将typealias 名称从X 更改为x,即

    class Y {
        typealias x = X<Int>
    }
    

    另外,DataSwift 中的预定义类型。这就是为什么您会收到 'X' is not a member type of 'Data' 错误。

    【讨论】:

    • 不,你的回答是回避问题,而不是解决问题。作为名称冲突问题的基础,必须使用相同的名称。如果所有名称都是唯一的 - 编程世界中将缺少名称冲突问题。但事实并非如此,几乎所有语言都有解决这个问题的机制(而且速度也很快)。如果它会说“swift 不提供解决此名称冲突的机制”,那么您的答案将是正确的。
    • 你能告诉我为什么 swift 允许不同的变量使用相同的名称吗?因为不推荐或以任何编程语言解决您使用它的方式。
    • 在我的问题中与变量无关,它与模块、结构和类型别名有关。它是题外话,但仅举个例子:C++ 提供了在不同命名空间中声明两个具有相同名称的变量的能力。我检查了 swift 也提供了这种能力。我用public let x: Int = ... 创建了A 和B 模块,用print(A.x); print(B.x) 创建了C 模块,所有三个模块都编译成功。但问题不在于变量。
    • 我的问题在 C++、C#、F#、Java、Scala、OCaml 中并不实际......在所有这些语言中,编译器都可以解析“它是什么命名空间或类型?”从上下文。这是我第一次发现类型隐藏命名空间的情况。这不是常见的命名空间概念:en.wikipedia.org/wiki/Namespace。它是边缘的。我的问题也不是关于语言比较。我询问了我在使用 Swift 编程时发现的具体问题。
    • OCaml 应该不在我的列表中。它有特定的模块系统。但是这个问题可以在 ocaml 中通过将模块名称绑定到另一个名称来解决。
    最近更新 更多