创建不同枚举的集合

时间:2016-07-05 08:30:50

标签: arrays swift loops enums nested

是否可以创建不同枚举类型的数组?

E.g:

MyEnums.swift:

class MyEnums {
    enum FirstEnum: String {
        case Type1, Type2, Type3
    }

    enum SecondEnum: String {
        case Type1, Type2, Type3
    }
}

IteratorManager.swift:

class IteratorManager {
    var enumsArray = [MyEnums]()

    func iterate() {
        for e in enumsArray {
            print(e.rawValue)
        }
    }
}

我在struct或enum中尝试了很多解决方案 - 扩展,协议,类中的分组(如上例所示) - 但没有任何作用。

2 个答案:

答案 0 :(得分:4)

是的,但你应该知道你是怎么做的。

枚举创建一个具体的类型。 Swift是Type Safe语言。 FirstEnum数组不允许包含FirstEnum类型的项目。

但是,有两种方法可以实现这一目标。 的 1。 Resuce的协议 2。输入谎言

我将采用这两种方法,但我永远不会建议使用第二种选择,尽管它似乎很简单并且避开。

我将从第二个开始。

enum FirstEnum: String {
    case Type1, Type2, Type3
}

enum SecondEnum: String {
    case Type1, Type2, Type3
}

让我们创建一些具体类型的枚举。

let firstEnum1 = FirstEnum.Type1
let firstEnum2 = FirstEnum.Type2
let secondEnum1 = SecondEnum.Type3

让我们使用第二个选项打包它们:

let a:[Any] = [firstEnum1, firstEnum2, secondEnum1] //works

让我们看看我们以后如何提取它:

for index in a {
 if let a = index as? FirstEnum {  //This is bad
    print(a.rawValue)
 }

 if let a = index as? SecondEnum { //Aweful
    print(a.rawValue)
 }
}

请参阅我们必须将其转换回我们插入的内容。我们必须使用期望,谁知道我们得到的可能是String而不是Enum。因为任何可以采取字面上的任何。

让我们看看我们如何通过第一个选项来解决这个问题:

let b:[RawRepresentable] = [firstEnum1, secondEnum1]  //Cant do so because of Associated Type

这段代码不起作用,因为RawRepresentable是一个不完整的类型。所以我们需要定义自己的协议。

protocol CustomStringRepresentableEnum {
   var rawValue: String { get }
}

当然,我们的Enums支持rawValue,因此我们可以追溯建立此协议。

 extension FirstEnum: CustomStringRepresentableEnum { }
 extension SecondEnum: CustomStringRepresentableEnum { }

现在我们可以创建一个具体已知类型的数组。

let b:[CustomStringRepresentableEnum] = [firstEnum1, firstEnum2, secondEnum1]

这很好,因为除了符合协议的东西之外,我们不允许输入任何东西。这是正确的Typed和约束,编译器将帮助你防止坏事发生,如错误的转换。

让我们用它来证明我们写了一些好的代码。

for index in b {
    print(index.rawValue)
}

就是这样。你可以在一个数组中使用不同的枚举,但不知何故它们需要是同构的。您可以使用Any 欺骗编译器并编写丑陋的代码或使用Protocols and Generics编写有效的和健壮的代码。选择是你的。

答案 1 :(得分:1)

@kandelvijaya 感谢您提供全面而全面的答案。

到目前为止,我已经开发了一些基于枚举初始化的属性:

MyEnums.swift:

    public static IEnumerable<IEnumerable<T>> GetPermutations<T>(this IEnumerable<T> enumerable)
    {
        var array = enumerable as T[] ?? enumerable.ToArray();

        var factorials = Enumerable.Range(0, array.Length + 1)
            .Select(Factorial)
            .ToArray();

        for (var i = 0L; i < factorials[array.Length]; i++)
        {
            var sequence = GenerateSequence(i, array.Length - 1, factorials);

            yield return GeneratePermutation(array, sequence);
        }
    }

    private static IEnumerable<T> GeneratePermutation<T>(T[] array, IReadOnlyList<int> sequence)
    {
        var clone = (T[])array.Clone();

        for (int i = 0; i < clone.Length - 1; i++)
        {
            Swap(ref clone[i], ref clone[i + sequence[i]]);
        }

        return clone;
    }

    private static int[] GenerateSequence(long number, int size, IReadOnlyList<long> factorials)
    {
        var sequence = new int[size];

        for (var j = 0; j < sequence.Length; j++)
        {
            var facto = factorials[sequence.Length - j];

            sequence[j] = (int)(number / facto);
            number = (int)(number % facto);
        }

        return sequence;
    }

    static void Swap<T>(ref T a, ref T b)
    {
        T temp = a;
        a = b;
        b = temp;
    }

    private static long Factorial(int n)
    {
        long result = n;

        for (int i = 1; i < n; i++)
        {
            result = result * i;
        }

        return result;
    }
}

IteratorManager.swift:

enum MyEnums {
    enum FirstEnum: String {
        case Type1, Type2, Type3
    }

    enum SecondEnum: String {
        case Type1, Type2, Type3
    }

    case First(FirstEnum)
    case Second(SecondEnum)

    var rawValue: String {
        switch self {
        case .First(let e):
            return e.rawValue
        case .Second(let e):
            return e.rawValue
        }
    }
}

填充数组并迭代:

class IteratorManager {
    var enumsArray = [MyEnums]()

    func iterate() {
        for e in enumsArray {
            print(e.rawValue)
        }
    }
}

它也是类型安全的(不像Any的解决方案)。

此外,我们可以定义一个示例协议:

let iteratorManager = IteratorManager()
iteratorManager.enumsArray = [MyEnums.First(MyEnums.FirstEnum.Type1), MyEnums.Second(MyEnums.SecondEnum.Type2)]
iteratorManager.iterate()

实施它:

protocol MyEnumsProtocol {
    var processedValue: String { get }
    static func typeGeneralDescription() -> String
}

并使用它:

enum MyEnums {
    enum FirstEnum: String, MyEnumsProtocol {
        case Type1, Type2, Type3

        var processedValue: String {
            return "-=\(self)-="
        }

        static func typeGeneralDescription() -> String {
            return "First enum type"
        }
    }

    enum SecondEnum: String, MyEnumsProtocol {
        case Type1, Type2, Type3

        var processedValue: String {
            return "-=\(self)-="
        }

        static func typeGeneralDescription() -> String {
            return "Second enum type"
        }
    }

    case First(FirstEnum)
    case Second(SecondEnum)

    var rawValue: String {
        switch self {
        case .First(let e):
            return e.rawValue
        case .Second(let e):
            return e.rawValue
        }
    }

    var subTypeDesc: String {
        switch self {
        case .First(let e):
            return "\(FirstEnum.typeGeneralDescription()): \(e.processedValue)"
        case .Second(let e):
            return "\(SecondEnum.typeGeneralDescription()): \(e.processedValue)"
        }
    }
}