【问题标题】:How do I get the count of a Swift enum?如何获得 Swift 枚举的计数?
【发布时间】:2015-01-21 13:51:26
【问题描述】:

如何确定 Swift 枚举中的事例数?

(我想避免使用manually enumerating through all the values,或者尽可能使用旧的“enum_count trick”。)

【问题讨论】:

    标签: swift enums count


    【解决方案1】:

    从 Swift 4.2 (Xcode 10) 开始,您可以声明 符合CaseIterable 协议,这适用于所有人 没有关联值的枚举:

    enum Stuff: CaseIterable {
        case first
        case second
        case third
        case forth
    }
    

    现在可以简单地获得案例数

    print(Stuff.allCases.count) // 4
    

    有关详细信息,请参阅

    【讨论】:

    • 在最新版本的 swift 中,它的抛出错误“类型'DAFFlow'不符合协议'RawRepresentable'”。为什么强迫我遵循这个?有什么想法吗?
    • @Satyam:什么是 DAFFlow?
    • 对不起,我忘了提到“DAFFlow”是一个简单的枚举,它不从任何其他协议继承。
    • 这是最好的解决方案,但只是为了清楚起见 - Apple 开发人员只有在 Xcode 10(以及因此 Swift 4.2)推出测试版后才能真正开始使用它(很可能在 2018 年 9 月 14 日左右) )。
    • @DaniSpringer:您可以在github.com/apple/swift-evolution/blob/master/proposals/… 找到血腥的细节。但由于编译器的自动类型推断,通常您不需要显式地使用该类型。
    【解决方案2】:

    我有a blog post 对此进行了更详细的说明,但只要您的枚举的原始类型是整数,您就可以通过这种方式添加计数:

    enum Reindeer: Int {
        case Dasher, Dancer, Prancer, Vixen, Comet, Cupid, Donner, Blitzen
        case Rudolph
    
        static let count: Int = {
            var max: Int = 0
            while let _ = Reindeer(rawValue: max) { max += 1 }
            return max
        }()
    }
    

    【讨论】:

    • 虽然很好,因为您不需要对值进行硬编码,但这将在每次调用时实例化每个枚举值。那是 O(n) 而不是 O(1)。 :(
    • 这是连续 Int 的一个很好的解决方案。我更喜欢稍作修改。将静态 count 属性转换为静态方法 countCases() 并将其分配给静态常量 caseCount,该常量是惰性的,可通过重复调用提高性能。
    • @ShamsAhmed:将计算的变量转换为静态变量。
    • 如果你错过了枚举中的一些值怎么办?例如case A=1, B=3 ?
    • 除了 enum 有一个 Int 原始值之外还有 2 个假设,但您忘了提及:带有 Int 原始值的 Swift 枚举不必从 0 开始(尽管这是默认行为) 并且它们的原始值可以是任意的,它们不必增加 1(即使这是默认行为)。
    【解决方案3】:

    Xcode 10 更新

    在枚举中采用CaseIterable 协议,它提供了一个静态的allCases 属性,其中包含所有枚举情况作为Collection。只需使用其count 属性即可知道枚举有多少个案例。

    请参阅 Martin 的答案以获取示例(并支持他的答案而不是我的答案)


    警告:以下方法似乎不再有效。

    我不知道有任何通用方法来计算枚举案例的数量。但是,我注意到枚举案例的 hashValue 属性是递增的,从零开始,并且顺序由声明案例的顺序决定。因此,最后一个枚举的哈希加一对应于案例的数量。

    以这个枚举为例:

    enum Test {
        case ONE
        case TWO
        case THREE
        case FOUR
    
        static var count: Int { return Test.FOUR.hashValue + 1}
    }
    

    count 返回 4。

    我不能说这是规则还是将来是否会改变,所以使用风险自负 :)

    【讨论】:

    • 靠无证特性生存,死于无证特性。我喜欢!
    • 我们真的不应该依赖hashValues来处理这些事情;我们所知道的是它是一些随机的唯一值 - 将来可能会根据一些编译器实现细节很容易改变;但总的来说,缺乏内置计数功能令人不安。
    • 如果您不介意明确设置case ONE = 0,则可以将hashValue 替换为rawValue
    • 这里的问题是使用了未记录的 hashValue 属性,所以我的建议是使用 rawValue 的记录属性。
    • 你已经硬编码了哪个常量是最高值的事实,最好更安全地使用像 static var count = 4 这样的东西,而不是将你的命运留给未来 Swift 实现的命运
    【解决方案4】:

    我定义了一个可重用的协议,它会根据 Nate Cook 发布的方法自动执行案例计数。

    protocol CaseCountable {
        static var caseCount: Int { get }
    }
    
    extension CaseCountable where Self: RawRepresentable, Self.RawValue == Int {
        internal static var caseCount: Int {
            var count = 0
            while let _ = Self(rawValue: count) {
                count += 1
            }
            return count
        }
    }
    

    然后我可以重用这个协议,例如:

    enum Planet : Int, CaseCountable {
        case Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune
    }
    //..
    print(Planet.caseCount)
    

    【讨论】:

    • 漂亮而优雅,应该是接受的答案恕我直言
    • 也许最好将count++ 更改为count+=1,因为++ 符号将在Swift 3 中被删除
    • 不能只用static var caseCount: Int { get }吗?为什么需要static func
    • 如果你错过了枚举中的一些值怎么办?例如case A=1, B=3 ?
    • @Sasho,那就不行了。这要求您的案例从0 开始并且没有间隔。
    【解决方案5】:

    创建静态 allValues 数组,如 answer 所示

    enum ProductCategory : String {
         case Washers = "washers", Dryers = "dryers", Toasters = "toasters"
    
         static let allValues = [Washers, Dryers, Toasters]
    }
    
    ...
    
    let count = ProductCategory.allValues.count
    

    这在您想要枚举值时也很有用,并且适用于所有 Enum 类型

    【讨论】:

    • 虽然不像扩展解决方案那样优雅而且非常手动,但我相信这是最有用的,因为它提供的不仅仅是计数。它为您提供值的顺序和所有值的列表。
    • 您也可以通过 static let count = allValues.count 将计数添加到枚举中。然后,如果需要,您可以将 allValues 设为私有。
    【解决方案6】:

    如果实现对使用整数枚举没有任何反对意见,您可以添加一个名为 Count 的额外成员值来表示枚举中的成员数量 - 请参见下面的示例:

    enum TableViewSections : Int {
      case Watchlist
      case AddButton
      case Count
    }
    

    现在您可以通过调用 TableViewSections.Count.rawValue 来获取枚举中的成员数,对于上面的示例,它将返回 2。

    当您在 switch 语句中处理枚举时,请确保在遇到您不期望的 Count 成员时抛出断言失败:

    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
      let currentSection: TableViewSections = TableViewSections.init(rawValue:section)!
      switch(currentSection) {
      case .Watchlist:
        return watchlist.count
      case .AddButton:
        return 1
      case .Count:
        assert(false, "Invalid table view section!")
      }
    }
    

    【讨论】:

    • 我喜欢这个解决方案,因为它会在添加更多枚举值时自动更改计数。但是请记住,这仅在枚举的 rawValues 以 0 开头时才有效。
    • 同意,有两个限制:必须是整数枚举并且必须从零开始并递增地继续。
    • 我认为 Swift 更强大的枚举的全部意义在于我们不必使用在 Objective-C 中使用的相同技巧:/
    【解决方案7】:

    这种函数能够返回枚举的计数。

    Swift 2

    func enumCount<T: Hashable>(_: T.Type) -> Int {
        var i = 1
        while (withUnsafePointer(&i) { UnsafePointer<T>($0).memory }).hashValue != 0 {
            i += 1
        }
        return i
    }
    

    Swift 3

    func enumCount<T: Hashable>(_: T.Type) -> Int {
       var i = 1
       while (withUnsafePointer(to: &i, {
          return $0.withMemoryRebound(to: T.self, capacity: 1, { return $0.pointee })
       }).hashValue != 0) {
          i += 1
       }
          return i
       }
    

    【讨论】:

    • 这不再适用于 Swift 3。试图找出正确的实现,但结果是空的
    • 如果紧邻enum末尾的内存地址是Hashable的同一类型,这将是非常不愉快的调试。
    【解决方案8】:

    带索引的字符串枚举

    enum eEventTabType : String {
        case Search     = "SEARCH"
        case Inbox      = "INBOX"
        case Accepted   = "ACCEPTED"
        case Saved      = "SAVED"
        case Declined   = "DECLINED"
        case Organized  = "ORGANIZED"
    
        static let allValues = [Search, Inbox, Accepted, Saved, Declined, Organized]
        var index : Int {
           return eEventTabType.allValues.indexOf(self)!
        }
    }
    

    计数:eEventTabType.allValues.count

    索引:objeEventTabType.index

    享受:)

    【讨论】:

      【解决方案9】:

      大家好,单元测试怎么样?

      func testEnumCountIsEqualToNumberOfItemsInEnum() {
      
          var max: Int = 0
          while let _ = Test(rawValue: max) { max += 1 }
      
          XCTAssert(max == Test.count)
      }
      

      这与安东尼奥的解决方案相结合:

      enum Test {
      
          case one
          case two
          case three
          case four
      
          static var count: Int { return Test.four.hashValue + 1}
      }
      

      在主代码中给你 O(1) 加上 你得到一个失败的测试 如果有人添加一个枚举案例 five 并且不更新的实现count.

      【讨论】:

        【解决方案10】:

        此函数依赖于 2 个未记录的当前(Swift 1.1)enum 行为:

        • enum 的内存布局只是case 的索引。如果案例计数为 2 到 256,则为 UInt8
        • 如果 enum 是从 invalid 案例索引位转换的,则其 hashValue0

        所以使用风险自负:)

        func enumCaseCount<T:Hashable>(t:T.Type) -> Int {
            switch sizeof(t) {
            case 0:
                return 1
            case 1:
                for i in 2..<256 {
                    if unsafeBitCast(UInt8(i), t).hashValue == 0 {
                        return i
                    }
                }
                return 256
            case 2:
                for i in 257..<65536 {
                    if unsafeBitCast(UInt16(i), t).hashValue == 0 {
                        return i
                    }
                }
                return 65536
            default:
                fatalError("too many")
            }
        }
        

        用法:

        enum Foo:String {
            case C000 = "foo"
            case C001 = "bar"
            case C002 = "baz"
        }
        enumCaseCount(Foo) // -> 3
        

        【讨论】:

        • 在发布和临时应用程序将崩溃
        • 这在模拟器中有效,但在真正的 64 位设备上无效。
        【解决方案11】:

        我写了一个简单的扩展,它为所有原始值为整数的枚举提供count 属性:

        extension RawRepresentable where RawValue: IntegerType {
            static var count: Int {
                var i: RawValue = 0
                while let _ = Self(rawValue: i) {
                    i = i.successor()
                }
                return Int(i.toIntMax())
            }
        }
        

        不幸的是,它将count 属性提供给OptionSetType,但它不能正常工作,所以这里有另一个版本,它需要明确符合CaseCountable 协议的任何枚举,您想要计算的情况:

        protocol CaseCountable: RawRepresentable {}
        extension CaseCountable where RawValue: IntegerType {
            static var count: Int {
                var i: RawValue = 0
                while let _ = Self(rawValue: i) {
                    i = i.successor()
                }
                return Int(i.toIntMax())
            }
        }
        

        这与 Tom Pelaia 发布的方法非常相似,但适用于所有整数类型。

        【讨论】:

          【解决方案12】:

          当然,它不是动态的,但对于许多用途,您可以通过添加到 Enum 的静态 var 来解决

          static var count: Int{ return 7 }

          然后将其用作EnumName.count

          【讨论】:

            【解决方案13】:
            enum EnumNameType: Int {
                case first
                case second
                case third
            
                static var count: Int { return EnumNameType.third.rawValue + 1 }
            }
            
            print(EnumNameType.count) //3
            

            enum EnumNameType: Int {
                case first
                case second
                case third
                case count
            }
            
            print(EnumNameType.count.rawValue) //3
            

            *在 Swift 4.2 (Xcode 10) 上可以使用:

            enum EnumNameType: CaseIterable {
                case first
                case second
                case third
            }
            
            print(EnumNameType.allCases.count) //3
            

            【讨论】:

              【解决方案14】:

              对于我的用例,在一个代码库中,多个人可以向一个枚举添加键,并且这些情况都应该在 allKeys 属性中可用,重要的是要根据枚举中的键验证 allKeys。 这是为了避免有人忘记将他们的键添加到所有键列表中。 将 allKeys 数组的计数(首先创建为一组以避免重复)与枚举中的键数相匹配可确保他们都在场。

              上面的一些答案显示了在 Swift 2 中实现这一点的方法,但在 Swift 3 中没有一个可行的方法。这是 Swift 3 格式的版本:

              static func enumCount<T: Hashable>(_ t: T.Type) -> Int {
                  var i = 1
                  while (withUnsafePointer(to: &i) {
                    $0.withMemoryRebound(to:t.self, capacity:1) { $0.pointee.hashValue != 0 }
                  }) {
                    i += 1
                  }
                  return i
              }
              
              static var allKeys: [YourEnumTypeHere] {
                  var enumSize = enumCount(YourEnumTypeHere.self)
              
                  let keys: Set<YourEnumTypeHere> = [.all, .your, .cases, .here]
                  guard keys.count == enumSize else {
                     fatalError("Missmatch between allKeys(\(keys.count)) and actual keys(\(enumSize)) in enum.")
                  }
                  return Array(keys)
              }
              

              根据您的用例,您可能只想在开发中运行测试以避免在每个请求上使用 allKeys 的开销

              【讨论】:

                【解决方案15】:

                你为什么把事情搞得这么复杂? Int 枚举的最简单的计数器是添加:

                case Count

                最后。还有...中提琴 - 现在你有数了 - 快速而简单

                【讨论】:

                • 这 a) 添加了一个无关的枚举大小写,并且 b) 如果枚举的原始类型不是 Int 则将不起作用。
                • 这实际上是一个不错的答案。然而,就像上面@Tom Pelaia 的回答一样,它要求原始值从0 开始,并且在序列中没有间隙。
                【解决方案16】:

                如果您不想将代码基于最后一个枚举,您可以在枚举中创建此函数。

                func getNumberOfItems() -> Int {
                    var i:Int = 0
                    var exit:Bool = false
                    while !exit {
                        if let menuIndex = MenuIndex(rawValue: i) {
                            i++
                        }else{
                            exit = true
                        }
                    }
                    return i
                }
                

                【讨论】:

                  【解决方案17】:

                  使用Int 类型枚举的Swift 3 版本:

                  protocol CaseCountable: RawRepresentable {}
                  extension CaseCountable where RawValue == Int {
                      static var count: RawValue {
                          var i: RawValue = 0
                          while let _ = Self(rawValue: i) { i += 1 }
                          return i
                      }
                  }
                  

                  致谢:基于 bzz 和 Nate Cook 的回答。

                  不支持泛型 IntegerType(在 Swift 3 中重命名为 Integer),因为它是一个非常分散的泛型类型,缺少很多功能。 successor 不再适用于 Swift 3。

                  请注意,Code Commander 对 Nate Cooks 回答的评论仍然有效:

                  虽然很好,因为您不需要对值进行硬编码,但这将 每次调用它时实例化每个枚举值。即 O(n) 而不是 O(1)。

                  据我所知,由于泛型类型不支持静态存储属性,因此在将其用作协议扩展(并且不像 Nate Cook 那样在每个枚举中实现)时,目前没有解决方法。

                  无论如何,对于小型枚举,这应该没有问题。一个典型的用例是 section.count 对应于 Zorayr 已经提到的UITableViews

                  【讨论】:

                    【解决方案18】:

                    扩展 Matthieu Riegler 的答案,这是一个针对 Swift 3 的解决方案,不需要使用泛型,并且可以使用带有 EnumType.elementsCount 的枚举类型轻松调用:

                    extension RawRepresentable where Self: Hashable {
                    
                        // Returns the number of elements in a RawRepresentable data structure
                        static var elementsCount: Int {
                            var i = 1
                            while (withUnsafePointer(to: &i, {
                                return $0.withMemoryRebound(to: self, capacity: 1, { return 
                                       $0.pointee })
                            }).hashValue != 0) {
                                i += 1
                            }
                            return i
                    }
                    

                    【讨论】:

                      【解决方案19】:
                      enum WeekDays : String , CaseIterable
                      {
                        case monday = "Mon"
                        case tuesday = "Tue"
                        case wednesday = "Wed"
                        case thursday = "Thu"
                        case friday = "Fri"
                        case saturday = "Sat"
                        case sunday = "Sun"
                      }
                      
                      var weekdays = WeekDays.AllCases()
                      
                      print("\(weekdays.count)")
                      

                      【讨论】:

                        【解决方案20】:

                        我通过创建一个协议 (EnumIntArray) 和一个全局实用函数 (enumIntArray) 为自己解决了这个问题,这使得向任何枚举添加一个“All”变量变得非常容易(使用 swift 1.2)。 “all”变量将包含枚举中所有元素的数组,因此您可以使用 all.count 进行计数

                        它只适用于使用 Int 类型的原始值的枚举,但也许它可以为其他类型提供一些灵感。

                        它还解决了我在上面和其他地方读到的“编号差距”和“迭代时间过长”的问题。

                        想法是将 EnumIntArray 协议添加到您的枚举中,然后通过调用 enumIntArray 函数定义一个“全部”静态变量,并为其提供第一个元素(如果编号中有间隙,则提供最后一个元素)。

                        因为静态变量只初始化一次,所以遍历所有原始值的开销只会影响您的程序一次。

                        示例(无间隙):

                        enum Animals:Int, EnumIntArray
                        { 
                          case Cat=1, Dog, Rabbit, Chicken, Cow
                          static var all = enumIntArray(Animals.Cat)
                        }
                        

                        示例(有间隙):

                        enum Animals:Int, EnumIntArray
                        { 
                          case Cat    = 1,  Dog, 
                          case Rabbit = 10, Chicken, Cow
                          static var all = enumIntArray(Animals.Cat, Animals.Cow)
                        }
                        

                        这是实现它的代码:

                        protocol EnumIntArray
                        {
                           init?(rawValue:Int)
                           var rawValue:Int { get }
                        }
                        
                        func enumIntArray<T:EnumIntArray>(firstValue:T, _ lastValue:T? = nil) -> [T]
                        {
                           var result:[T] = []
                           var rawValue   = firstValue.rawValue
                           while true
                           { 
                             if let enumValue = T(rawValue:rawValue++) 
                             { result.append(enumValue) }
                             else if lastValue == nil                     
                             { break }
                        
                             if lastValue != nil
                             && rawValue  >  lastValue!.rawValue          
                             { break }
                           } 
                           return result   
                        }
                        

                        【讨论】:

                          【解决方案21】:

                          或者你可以在枚举之外定义_count,然后静态附加:

                          let _count: Int = {
                              var max: Int = 0
                              while let _ = EnumName(rawValue: max) { max += 1 }
                              return max
                          }()
                          
                          enum EnumName: Int {
                              case val0 = 0
                              case val1
                              static let count = _count
                          }
                          

                          这样,无论您创建多少枚举,它都只会被创建一次。

                          (如果static 这样做,请删除此答案)

                          【讨论】:

                            【解决方案22】:

                            以下方法来自CoreKit,与其他人建议的答案相似。这适用于 Swift 4。

                            public protocol EnumCollection: Hashable {
                                static func cases() -> AnySequence<Self>
                                static var allValues: [Self] { get }
                            }
                            
                            public extension EnumCollection {
                            
                                public static func cases() -> AnySequence<Self> {
                                    return AnySequence { () -> AnyIterator<Self> in
                                        var raw = 0
                                        return AnyIterator {
                                            let current: Self = withUnsafePointer(to: &raw) { $0.withMemoryRebound(to: self, capacity: 1) { $0.pointee } }
                                            guard current.hashValue == raw else {
                                                return nil
                                            }
                                            raw += 1
                                            return current
                                        }
                                    }
                                }
                            
                                public static var allValues: [Self] {
                                    return Array(self.cases())
                                }
                            }
                            

                            enum Weekdays: String, EnumCollection {
                                case sunday, monday, tuesday, wednesday, thursday, friday, saturday
                            }
                            

                            那么您只需拨打Weekdays.allValues.count即可。

                            【讨论】:

                              【解决方案23】:
                              struct HashableSequence<T: Hashable>: SequenceType {
                                  func generate() -> AnyGenerator<T> {
                                      var i = 0
                                      return AnyGenerator {
                                          let next = withUnsafePointer(&i) { UnsafePointer<T>($0).memory }
                                          if next.hashValue == i {
                                              i += 1
                                              return next
                                          }
                                          return nil
                                      }
                                  }
                              }
                              
                              extension Hashable {
                                  static func enumCases() -> Array<Self> {
                                      return Array(HashableSequence())
                                  }
                              
                                  static var enumCount: Int {
                                      return enumCases().enumCount
                                  }
                              }
                              
                              enum E {
                                  case A
                                  case B
                                  case C
                              }
                              
                              E.enumCases() // [A, B, C]
                              E.enumCount   //  3
                              

                              但在使用非枚举类型时要小心。一些解决方法可能是:

                              struct HashableSequence<T: Hashable>: SequenceType {
                                  func generate() -> AnyGenerator<T> {
                                      var i = 0
                                      return AnyGenerator {
                                          guard sizeof(T) == 1 else {
                                              return nil
                                          }
                                          let next = withUnsafePointer(&i) { UnsafePointer<T>($0).memory }
                                          if next.hashValue == i {
                                              i += 1
                                              return next
                                          }
                              
                                          return nil
                                      }
                                  }
                              }
                              
                              extension Hashable {
                                  static func enumCases() -> Array<Self> {
                                      return Array(HashableSequence())
                                  }
                              
                                  static var enumCount: Int {
                                      return enumCases().count
                                  }
                              }
                              
                              enum E {
                                  case A
                                  case B
                                  case C
                              }
                              
                              Bool.enumCases()   // [false, true]
                              Bool.enumCount     // 2
                              String.enumCases() // []
                              String.enumCount   // 0
                              Int.enumCases()    // []
                              Int.enumCount      // 0
                              E.enumCases()      // [A, B, C]
                              E.enumCount        // 4
                              

                              【讨论】:

                                【解决方案24】:

                                它可以使用包含枚举的最后一个值加一的静态常量。

                                enum Color : Int {
                                    case  Red, Orange, Yellow, Green, Cyan, Blue, Purple
                                
                                    static let count: Int = Color.Purple.rawValue + 1
                                
                                    func toUIColor() -> UIColor{
                                        switch self {
                                            case .Red:
                                                return UIColor.redColor()
                                            case .Orange:
                                                return UIColor.orangeColor()
                                            case .Yellow:
                                                return UIColor.yellowColor()
                                            case .Green:
                                                return UIColor.greenColor()
                                            case .Cyan:
                                                return UIColor.cyanColor()
                                            case .Blue:
                                                return UIColor.blueColor()
                                            case .Purple:
                                                return UIColor.redColor()
                                        }
                                    }
                                }
                                

                                【讨论】:

                                  【解决方案25】:

                                  这是次要的,但我认为更好的 O(1) 解决方案如下(如果您的枚举是从 x 开始的 Int 等):

                                  enum Test : Int {
                                      case ONE = 1
                                      case TWO
                                      case THREE
                                      case FOUR // if you later need to add additional enums add above COUNT so COUNT is always the last enum value 
                                      case COUNT
                                  
                                      static var count: Int { return Test.COUNT.rawValue } // note if your enum starts at 0, some other number, etc. you'll need to add on to the raw value the differential 
                                  }
                                  

                                  我仍然认为当前选择的答案是所有枚举的最佳答案,除非您正在使用 Int,否则我推荐此解决方案。

                                  【讨论】:

                                  • 向您的枚举添加一个实际上并不代表枚举类型的值是一种不好的代码气味。我发现甚至很难证明包括“ALL”或“NONE”是合理的,尽管有时它可能很诱人。包含一个“COUNT”只是为了解决这个问题非常糟糕。
                                  • 臭吗?如果你想这么称呼它。表现?是的。由开发人员决定利弊。这实际上与上面 Zorayr 的答案相同,他对此进行了更详细的说明,并且新接受的答案也相似。但是直到 swift 为它添加一个 api;这是我们中的一些人决定使用的。您可以添加一个函数来验证 guards 与 COUNT 的枚举值并引发错误、返回 false 等,以解决您对类型表示的担忧。
                                  猜你喜欢
                                  • 2010-11-08
                                  • 1970-01-01
                                  • 1970-01-01
                                  • 1970-01-01
                                  • 1970-01-01
                                  • 2020-10-19
                                  • 1970-01-01
                                  • 1970-01-01
                                  相关资源
                                  最近更新 更多