如何使用带有嵌套枚举的 switch 语句?

How do you use a switch statement with a nested enum?

我为 Instagram 端点创建了一个枚举,其嵌套枚举类似于 Moya

enum Instagram {
    enum Media {
        case Popular
        case Shortcode(id: String)
        case Search(lat: Float, lng: Float, distance: Int)
    }
    enum Users {
        case User(id: String)
        case Feed
        case Recent(id: String)
    }
}

我想return每个端点的路径。

extension Instagram: TargetType {
    var path: String {
        switch self {
        case .Media.Shortcode(let id):
            return "/media/shortcode"
        }
    }
}

但是我在上面的 path.

的 switch 语句中遇到错误

Enum case Shortcode is not a member of type Instagram

如何修复?

Advanced Practical Enums

Enum case Search is not a member of type Instagram

正如编译器所说,Search 不是类型 Instagram 的成员。它只是Instagram范围内的枚举。您必须在 Instagram

中创建一个 Search 的实例成员
struct Instagram {
    enum Media {
        case Search(lat: Float, lng: Float, distance: Int)
    }
    // something like:
     var media = .Search(lat: 0, lng: 0, distance: 0) 
    // I'm not sure this one is right syntax
    // because I can't check it right now.
    // please just get the idea
}
extension Instagram: TargetType {
    var path: String {
        switch self.media {
        case .Search(let _, let _, let _):
            return "/media/search"
        }
    }
}

您的体系结构存在一些问题。您应该知道何时以及为何需要使用扩展和协议,以及您应该如何构建代码块。

  1. 如果您的类型需要符合该协议,请随意使用它 确保您设定自己的标准。我什至没有在您提到的 github 项目中看到这一点。
  2. 扩展是拥有原始类型并在项目的其他部分扩展其功能的好方法。为什么你应该在声明后立即扩展类型对我来说没有意义。它的一个很好的用例是 String 类型已扩展为支持 URL 编码值:
private extension String {
    var URLEscapedString: String {
        return self.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLHostAllowedCharacterSet())!
    }
}
  1. 当您使用这种类型的 switch-case 块时
switch self {
    case .Zen:
        return "/zen"
    case .UserProfile(let name):
        return "/users/\(name.URLEscapedString)"
    case .UserRepositories(let name):
        return "/users/\(name.URLEscapedString)/repos"
}

案例中的值应该是self的成员。这就是为什么它找不到类型的原因。该类型在 Instagram 枚举中声明,但它在自身中没有价值。它在 Media 内部具有价值。因此,将您的媒体相关功能移动到媒体声明中并在那里访问它们。这样 self 指的是媒体。这是我的完整工作代码:


private extension String {
    var URLEscapedString: String {
        return self.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLHostAllowedCharacterSet())!
    }
}</p>

<p>public enum Instagram {</p>

<pre><code>public enum Media {
    case Search(String)

    var path:String {
        switch self {

        case Media.Search(let keyword):
            return "/media/search/\(keyword.URLEscapedString)"
        }
    }
}

}

var me = Instagram.Media.Search("me") print(me.path)

  1. 作为一条建议,在构建整个架构的每个步骤中,请问自己该段代码是否属于该类型或是否应该公开访问。在这种情况下,将搜索移至媒体是完全有意义的,因为您正在搜索媒体。您可以为用户添加相同的模式,并在用户下搜索 returns 不同的值。

通过为嵌套枚举添加关联值,您可以使用 switch 语句访问它。

enum Instagram {
    enum MediaEndpoint {
        case Search(lat: Float, lng: Float, distance: Int)
    }
    case Media(MediaEndpoint)
}

extension Instagram: TargetType {
    var path: String {
        switch self {
        case .Media(.Search):
            return "/media/search"
        }
    }
}

// Demo

protocol TargetType {
    var path: String { get }
}

class MoyaProvider<Target: TargetType> {
    func request(_ target: Target, completion: @escaping () -> ()) {}
}

let provider = MoyaProvider<Instagram>()
provider.request(.Media(.Search(lat: 0, lng: 0, distance: 0))) {}

出于某些原因,我要添加一个更笼统的答案。

  1. 这是关于嵌套枚举和 switch 语句的唯一未决问题。 .
  2. 唯一合法的答案没有说明如何将嵌套枚举的值分配给符号。语法对我来说不直观。
  3. None 的其他答案有大量案例。
  4. 嵌套 3 层的枚举更能说明所需的语法。使用 efremidze 答案还是花了我一段时间才弄明白。

enum Action {
    case fighter(F)
    case weapon(W)

    enum F {
        case attack(A)
        case defend(D)
        case hurt(H)

        enum A {
            case fail
            case success
        }
        enum D {
            case fail
            case success
        }
        enum H {
            case none
            case some
        }
    }
    enum W {
        case swing
        case back
    }
}

// Matches "3 deep"
let action = Action.fighter(.attack(.fail))
// Matches "1 deep" because more general case listed first.
let action2 = Action.weapon(.swing)

switch action {
case .fighter(.attack(.fail)):
    print("3 deep")
case .weapon:
    print("1 deep")
case .weapon(.swing):
    print("2 deep to case")
case .fighter(.attack):
    print("2 deep to another enum level")
default:
    print("WTF enum")
}