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

时间:2016-01-16 00:58:15

标签: swift enums switch-statement

我使用类似于Moya的嵌套枚举为Instagram端点创建了一个枚举。

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)
    }
}

我想返回每个端点的路径。

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

但是我在path上面的switch语句中收到错误。

  

枚举案例Shortcode不是Instagram

类型的成员

如何解决?

Advanced Practical Enums

4 个答案:

答案 0 :(得分:33)

由于一些原因,我正在添加更一般的答案。

  1. 这是有关嵌套枚举和switch语句的唯一未解决的问题。 The other one is sadly closed
  2. 唯一合法的答案并未说明如何将嵌套枚举的值分配给符号。语法对我来说不直观。
  3. 其他答案都没有大量案例。
  4. 嵌套3层深度的枚举更能说明所需的语法。使用efremidze回答还需要一段时间来解决它。
  5. 
    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")
    }
    

答案 1 :(得分:14)

通过为嵌套枚举添加关联值,您可以使用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))) {}

答案 2 :(得分:4)

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

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

      案件中的价值应该是自我的一员。这就是它无法找到类型的原因。该类型在Instagram枚举中声明,但它在自我中没有价值。它在媒体内部具有价值。因此,将媒体相关功能转移到媒体声明中并在那里访问它们。这就是自我指的是媒体。这是我的完整工作代码:

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

      public enum Instagram {

      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. 作为一条建议,在构建整个架构的每一步中,只要质疑这段代码是属于该类型还是应该公开访问。在这种情况下,将搜索移动到媒体是完全合理的,因为您正在搜索媒体。您可以为User之类的内容添加相同的模式,并在用户下进行搜索,返回不同的值。

答案 3 :(得分:1)

  

枚举案例搜索不是Instagram类型的成员

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

中创建一个Instagram实例的成员
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"
        }
    }
}