是否可以创建不同枚举类型的数组?
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中尝试了很多解决方案 - 扩展,协议,类中的分组(如上例所示) - 但没有任何作用。
答案 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)"
}
}
}