如何更改存储在局部变量中的 Struct 元类型

问题描述 投票:0回答:2

我正在尝试制作一个服装推荐应用程序,但遇到了问题。我有一个名为衣柜的属性,我想在其中存储与用户选择的活动类型相关的所有衣物。

我的方法如下:

func recommendClothing(for conditions: WeatherForSelection, type: ActivityType){
        temperature = conditions.feelsLike ?? 0
        isWindy = conditions.windSpeed ?? 0 > 5
        
        let wardrobe = CyclingClothing.self
    
        
        clothing = [
            Clothing(title: "Head", description: wardrobe.Head.forTemperature(temperature).name, image: wardrobe.Head.forTemperature(temperature).image),
            Clothing(title: "Base Layer", description: wardrobe.BaseLayer.forTemperature(temperature).name, image: wardrobe.BaseLayer.forTemperature(temperature).image),
            Clothing(title: "Mid Layer", description: wardrobe.MidLayer.forTemperature(temperature).name, image: wardrobe.MidLayer.forTemperature(temperature).image),
            Clothing(title: "Legs", description: wardrobe.Legs.forTemperature(temperature).name, image: wardrobe.Legs.forTemperature(temperature).image),
            Clothing(title: "Hands", description: wardrobe.Hands.forTemperature(temperature).name, image: wardrobe.Hands.forTemperature(temperature).image),
            Clothing(title: "Feet", description: wardrobe.Feet.forTemperature(temperature).name, image: wardrobe.Feet.forTemperature(temperature).image)
            
        ]
        
        if wardrobe.Shell.forTemperature(temperature) != .none {
            clothing.append(Clothing(title: "Shell", description: wardrobe.Shell.forTemperature(temperature).name, image: wardrobe.Shell.forTemperature(temperature).image))
        }
        
        if isWindy {
            clothing.append(Clothing(title: "Wind Protection", description: "Windproof Layer", image: "windproof"))
        }
        if conditions.isRaining ?? false {
            clothing.append(Clothing(title: "Rain Protection", description: "Waterproof Layer", image: "raincoat"))
        }
        
    }

我想,我只需打开输入type并根据它选择衣柜即可。但接下来我必须定义衣柜的类型,它总是不同的。所以我尝试将 Clothing 结构放入一个名为 Wardrobe 的主结构中,并仅选择衣柜的子结构,但这对我来说也不起作用......我也尝试了一些协议和扩展的恶作剧,但自从我'我对此还很陌生,它也不起作用......

类可以继承工作吗?

有没有办法让它工作或者我必须一起改变逻辑?

服装结构示例如下所示:

struct CyclingClothing {
    
    //MARK: - Head
    enum Head {
        case helmet, headBand, lightCap, winterCap
        
        static func forTemperature(_ temperature: Double) -> Head {
            switch temperature {
            case ..<5:
                    .winterCap
            case 5..<10:
                    .lightCap
            case 10..<15:
                    .headBand
            case 15..<30:
                    .helmet
            default:
                    .helmet
            }
        }
        
        var name: String {
            switch self {
            case .helmet:
                "Just a Helmet"
            case .headBand:
                "Headband"
            case .lightCap:
                "Skullcap"
            case .winterCap:
                "Winter Cap"
            }
        }
        
        var image: String {
            switch self {
                
            case .helmet:
                "helmet"
            case .headBand:
                "headband"
            case .lightCap:
                "light_cap"
            case .winterCap:
                "winter_cap"
            }
        }
    }
    
    //MARK: - Base Layer
    enum BaseLayer {
        case none, lightBase, thermalBase
        
        static func forTemperature(_ temperature: Double) -> BaseLayer {
            switch temperature {
            case ..<10:
                    .thermalBase
            case 10..<20:
                    .lightBase
            default:
                    .none
            }
        }
        
        var name: String {
            switch self {
            case .none:
                "No Base Layer"
            case .lightBase:
                "Light"
            case .thermalBase:
                "Thermal"
            }
        }
        
        var image: String {
            switch self {
            case .none:
                "body"
            case .lightBase:
                "light_base"
            case .thermalBase:
                "thermal_base"
            }
        }
    }
    
    //MARK: - Mid Layer
    enum MidLayer {
        case jersey, longJersey, thermalJersey
        
        static func forTemperature(_ temperature: Double) -> MidLayer {
            switch temperature {
            case ..<10:
                    .thermalJersey
            case 10..<20:
                    .longJersey
            default:
                    .jersey
            }
        }
        
        var name: String {
            switch self {
            case .jersey:
                "Jersey"
            case .longJersey:
                "Long Sleeved Jersey"
            case .thermalJersey:
                "Thermal Jersey"
            }
        }
        
        var image: String{
            switch self {
            case .jersey:
                "jersey"
            case .longJersey:
                "long_jersey"
            case .thermalJersey:
                "thermal_jersey"
            }
        }
    }
    
    //MARK: - Shell
    enum Shell {
        case none, lightJacket, insulatedJacket
        
        static func forTemperature(_ temperature: Double) -> Shell {
            switch temperature {
            case ..<5:
                    .insulatedJacket
            case 5..<15:
                    .lightJacket
            default:
                    .none
            }
        }
        
        var name: String {
            switch self {
            case .none:
                "No Shell"
            case .lightJacket:
                "Light Jacket"
            case .insulatedJacket:
                "Insulated Jacket"
            }
        }
        
        var image: String {
            switch self {
            case .none:
                "no_shell"
            case .lightJacket:
                "light_jacket"
            case .insulatedJacket:
                "insulated_jacket"
            }
        }
        
    }
    
    //MARK: - Legs
    enum Legs {
        case shorts, longBibs, thermalBibs
        
        static func forTemperature(_ temperature: Double) -> Legs {
            switch temperature {
            case ..<10:
                    .thermalBibs
            case 10..<18:
                    .longBibs
            default:
                    .shorts
            }
        }
        
        var name: String {
            switch self {
            case .shorts:
                "Bib Shorts"
            case .longBibs:
                "Long Bibs"
            case .thermalBibs:
                "Thermal Bibs"
            }
        }
        
        var image: String {
            switch self {
            case .shorts:
                "bib_shorts"
            case .longBibs:
                "long_bibs"
            case .thermalBibs:
                "thermal_bibs"
            }
        }
    }
    
    //MARK: - Hands
    enum Hands {
        case longGloves, insulatedGloves, summerGloves
        
        static func forTemperature(_ temperature: Double) -> Hands {
            switch temperature {
            case ..<10:
                    .insulatedGloves
            case 10..<15:
                    .longGloves
            default:
                    .summerGloves
            }
        }
        
        var name: String {
            switch self {
            case .summerGloves:
                "Summer Gloves"
            case .longGloves:
                "Long Gloves"
            case .insulatedGloves:
                "Insulated Gloves"
            }
        }
        var image: String {
            switch self {
            case .summerGloves:
                "gloves"
            case .longGloves:
                "long_gloves"
            case .insulatedGloves:
                "insulated_gloves"
            }
        }
    }
    
    //MARK: - Feet
    enum Feet {
        case summerSocks, warmSocks, shoeCovers, winterShoes
        
        static func forTemperature(_ temperature: Double) -> Feet {
            switch temperature {
            case ..<3:
                return .winterShoes
            case 3..<7:
                return .shoeCovers
            case 7..<15:
                return .warmSocks
            default:
                return .summerSocks
            }
        }
        
        var name: String {
            switch self {
            case .summerSocks:
                "Light Socks"
            case .warmSocks:
                "Warm Socks"
            case .shoeCovers:
                "Shoe Covers"
            case .winterShoes:
                "Winter Shoes"
            }
        }
        
        var image: String {
            switch self {
            case .summerSocks:
                "socks"
            case .warmSocks:
                "warm_socks"
            case .shoeCovers:
                "covers"
            case .winterShoes:
                "winter_shoes"
            }
        }
    }
}



swift struct metatype
2个回答
0
投票

您的代码中可能还有其他问题,但要修复

wardrobe
,我建议您将
CyclingClothing
struct
更改为
enum

然后从函数中删除

wardrobe
常量,并将其所有使用替换为
CyclingClothing

比如说

Clothing(title: "Head", 
         description: CyclingClothing.Head.forTemperature(temperature).name, 
         image: CyclingClothing.Head.forTemperature(temperature).image)
        

0
投票

您的代码使用类型作为值,这种方式使用起来非常棘手。

您将遇到的第一个问题是您无法有条件地选择

wardrobe
值来选择两种类型中的一种。例如。这行不通:

let wardrobe = cycling ? CyclingWardrobe.self : WalkingWardrobe.self

因为

CyclingWardrobe
WalkingWardrobe
是两种完全不相关的类型。它们可能在结构上恰好相似,但这无关紧要。这类似于拥有
let i = small ? Int8() : Int64()

为了使它们像这样具有互操作性,您需要引入一个抽象(超类或协议),将它们聚集在一个公共类型下,该类型表示它们都可以处理的操作。但在这种情况下,您可以按名称访问嵌套类型,并且没有(简单)方法对其进行抽象。这一切很快就会变得一团糟。

相反,您应该直接使用对象/值。无需在类型级别进行“元”。

  1. 删除所有枚举。
  2. 创建一个协议来描述每个衣柜的共同点。
    • 在这种情况下,它是为
      head
      baseLayer
      midLayer
      等提供某些东西的能力。将它们捕获为 协议的要求(函数或变量)。
  3. 创建符合
    Wardrobe
    协议的不同类型,以独特的方式实现这些要求。
  4. 最后,创建一个“选择器”函数,根据活动,返回正确类型的新衣柜。

这是一个入门示例:

struct Clothing {
    let title: String
    let description: String
    let image: String
}

struct WeatherConditions {
    let temperature: Double
    let isWindy: Bool
    let isRaining: Bool
}

enum ActivityType {
    case cycling
    case walking
}

// A Wardrobe is a thing that can provide you with a particular kind of clothing
protocol Wardrobe {
    // TODO: should these be optional?
    // E.g. imagine if there was `ActivityType.beachParty`
    var head: Clothing { get }
    var baseLayer: Clothing { get }
    var midLayer: Clothing { get }
    var legs: Clothing { get }
    var hands: Clothing { get }
    var feet: Clothing { get }

    // Add a way for wardrobes to add other stuff, if necessary.
    var other: [Clothing] { get }
}

extension Wardrobe {
    func recommendClothing() -> [Clothing] {
        return [head, baseLayer, midLayer, legs, hands, feet] + other
    }
}

func chooseWardrobe(activity: ActivityType, conditions: WeatherConditions) -> any Wardrobe {
        switch activity {
        case .cycling:
            return CyclingWardrobe(forConditions: conditions)
        case .walking:
            // Example TODO: Create a WalkingWardrobe that conforms to Wardrobe
            fatalError("Implement me!")
        }
    }

struct CyclingWardrobe: Wardrobe {
    let weatherConditions: WeatherConditions
    
    public init(forConditions weatherConditions: WeatherConditions) {
        self.weatherConditions = weatherConditions
    }

    private var temperature: Double { return weatherConditions.temperature }

    var head: Clothing {
        switch temperature {
        case ..<5:    return Clothing(title: "Head", description: "Winter Cap",    image: "winter_cap")
        case 5..<10:  return Clothing(title: "Head", description: "Skullcap",      image: "light_cap" )
        case 10..<15: return Clothing(title: "Head", description: "Headband",      image: "headband"  )
        default:      return Clothing(title: "Head", description: "Just a Helmet", image: "helmet"    )
        }
    }
    var baseLayer: Clothing {
        switch temperature {
        case ..<10:   return Clothing(title: "Base Layer", description: "Thermal",       image: "thermal_base")
        case 10..<20: return Clothing(title: "Base Layer", description: "Light",         image: "light_base"  )
        default:      return Clothing(title: "Base Layer", description: "No Base Layer", image: "body"        )
        }
    }

    var midLayer: Clothing {
        switch temperature {
        case ..<10:   return Clothing(title: "Mid layer", description: "Thermal Jersey", image: "thermal_jersey")
        case 10..<20: return Clothing(title: "Mid layer", description: "Long Sleeved Jersey", image: "long_jersey")
        default:      return Clothing(title: "Mid layer", description: "Jersey", image: "jersey")
        }
    }

    var legs: Clothing {
        switch temperature {
        case ..<10:   return Clothing(title: "Legs", description: "Thermal Bibs", image: "thermal_bibs")
        case 10..<18: return Clothing(title: "Legs", description: "Long Bibs",    image: "long_bibs"   )
        default:      return Clothing(title: "Legs", description: "Bib Shorts",   image: "bib_shorts"  )
        }
    }

    var hands: Clothing {
        switch temperature {
        case ..<10:   return Clothing(title: "Hands", description: "Insulated Gloves", image: "insulated_gloves")
        case 10..<15: return Clothing(title: "Hands", description: "Long Gloves",      image: "long_gloves"     )
        default:      return Clothing(title: "Hands", description: "Summer Gloves",    image: "gloves"          )
        }
    }
    
    var feet: Clothing {
        switch temperature {
        case ..<3:   return Clothing(title: "Feet", description: "Winter Shoes",      image: "winter_shoes")
        case 3..<7:  return Clothing(title: "Feet", description: "Shoe Covers" ,      image: "covers"      )
        case 7..<15: return Clothing(title: "Feet", description: "Warm Socks Covers", image: "warm_socks"  )
        default:     return Clothing(title: "Feet", description: "Light Socks",       image: "socks"       )
        }
    }

    var shell: Clothing? {
        switch temperature {
        case ..<5:   return Clothing(title: "Mid Layer", description: "Insulated Jacket", image: "insulated_jacket")
        case 5..<15: return Clothing(title: "Mid Layer", description: "Light Jacket",     image: "light_jacket"    )
        default:     return nil
        }
    }

    var other: [Clothing] {
        var clothing = [Clothing]()

        if let shell = self.shell {
            clothing.append(shell)
        }

        if weatherConditions.isWindy {
            clothing.append(Clothing(title: "Wind Protection", description: "Windproof Layer", image: "windproof"))
        }

        if weatherConditions.isRaining {
            clothing.append(Clothing(title: "Rain Protection", description: "Waterproof Layer", image: "raincoat"))
        }
        
        return clothing
    }
}

您的来电者变得非常简单。它会咨询挑选器来为活动选择正确的衣柜,然后向衣柜询问所有推荐的衣服。勒芬。

let weather = WeatherConditions(temperature: 10, isWindy: false, isRaining: false)

let clothing = chooseWardrobe(activity: .cycling, conditions: weather).recommendClothing()

for article in clothing {
    print("\(article.title): \(article.description)")
}
© www.soinside.com 2019 - 2024. All rights reserved.