代码之家  ›  专栏  ›  技术社区  ›  tierriminator

Swift枚举案例访问级别

  •  3
  • tierriminator  · 技术社区  · 7 年前

    我知道,Swift不允许在enum中重新定义案例的访问级别,这意味着以下是不可能的

    public enum Foo {
        private case Bar
        private indirect case Ind(Foo)
        public init() {
            self = Bar
        }
    }
    

    谁能告诉我为什么这是不允许的?在某些情况下,隐藏枚举的案例并提供初始化器来初始化此类案例是可行的,因此我真的看不出拒绝此功能的动机。

    编辑:

    考虑以下纯功能树结构的示例:

    public enum Tree<T: Comparable> {
        case Leaf
        indirect case Node(T, Tree, Tree, Int)
        public init() {
            self = .Leaf
        }
        
        public func height() -> Int {
            switch self {
            case .Leaf:
                return 0
            case let .Node(_, _, _, h):
                return h
            }
        }
        // functions for add and remove, etc.
    }
    

    为了更好地运行(这在实现自平衡二叉树时是可取的),可能需要将树的高度作为关联值包含在 Node 案例但这会带来封装问题,正如人们现在可能构造的那样 节点 非法高度案件。如果可以覆盖案例的访问级别,或者允许在枚举中存储常量,则可以解决此问题。

    2 回复  |  直到 4 年前
        1
  •  3
  •   Alexander    5 年前

    敏捷的 switch 声明必须详尽无遗。假设您的客户 public enum Foo 尝试在 转换 . 如果 .bar 案子是私人的,怎么办 转换 应该处理吗?

    案例是枚举的公共API的一部分。如果希望将它们私有化,请将它们封装在仅公开公共操作的结构中。

    更新:随着 SE-0192 在Swift 5中 @unknown default: 介绍了语法。这在您有 enum 您已经处理了所有当前存在的案例,但希望通过指定 default 行为

        2
  •  0
  •   Monolith Mehul Kabaria    5 年前

    您可以通过使用私有构造函数添加类型来“实现”该行为。

    下面是一个示例:

    public enum Foo {
        case a(Barrier)
        case b(Int, Int, Barrier)
    
        public init(x: X?) {
            if let x: X = x {
                self = .b(x.y, x.z, Barrier())
            } else {
                self = .a(Barrer())
            }
        }
    
        /// Use Foo constructor!
        public struct Barrier {
            fileprivate init() { }
        }
    }
    

    有些人仍然可以创建没有任何意义但看起来很乏味的实例:

    func createB() -> Foo {
        switch Foo(x: nil) {
        case .a(let barrier): return Foo.b(1, 2, barrier)
        case .b(_, _, let barrier): return Foo.b(1, 2, barrier)
    }
    

    还要确保枚举确实优于结构或对象。