You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将Fruit结构体映射为遵循FruitProtocol的对应结构体?

问题:可失败初始化器无法将Fruit转换为AppleFruit/PearFruit?

场景说明

我们定义了Fruit结构体,内部包含FruitType枚举、id属性,以及可选的Apple和Pear结构体实例。需要创建遵循FruitProtocol协议的AppleFruit和PearFruit结构体,它们需包含水果id以及对应类型的Apple或Pear数据。尝试实现的可失败初始化器无法正常工作,使用return和self=都无效,请问问题出在哪?

初始代码

struct Fruit {
    enum FruitType {
        case apple
        case pear
        case unknown
    }

    let id: String
    let type: FruitType
    let apple: Apple?
    let pear: Pear?
}

struct Apple {
    let something: String 
}

struct Pear {
    let somethingElse: String
}

尝试的初始化器代码

init?(from fruit: Fruit) {
    switch fruit.type {
    case .apple:
        guard let apple = fruit.apple else { return nil }

        Apple(...)
    case .pear:
        guard let pear = coreAsset.pear else { return nil }
        
        Pear(...)
    default:
        self = nil
    }
}

问题分析与解决方案

核心问题点

  1. 未正确初始化目标结构体属性:代码里在case .apple分支直接调用Apple(...),但AppleFruit应该包含id和apple两个属性,需要给当前结构体的这些属性赋值,而非仅创建Apple实例。
  2. 变量名笔误:coreAsset.pear应改为fruit.pear,初始化器的参数是fruit。
  3. 结构体可失败初始化器用法错误:值类型(结构体)的可失败初始化器不能通过self = nil触发失败,正确做法是使用return nil。
  4. 缺少协议与目标结构体定义:原代码未给出FruitProtocol、AppleFruit和PearFruit的具体定义,这是实现转换的基础。

正确实现代码

先补充协议和目标结构体的定义,再实现正确的可失败初始化器:

// 定义通用协议
protocol FruitProtocol {
    var id: String { get }
}

// Apple专属结构体,遵循协议
struct AppleFruit: FruitProtocol {
    let id: String
    let apple: Apple
    
    // 可失败初始化器
    init?(from fruit: Fruit) {
        guard fruit.type == .apple, let apple = fruit.apple else {
            return nil
        }
        self.id = fruit.id
        self.apple = apple
    }
}

// Pear专属结构体,遵循协议
struct PearFruit: FruitProtocol {
    let id: String
    let pear: Pear
    
    // 可失败初始化器
    init?(from fruit: Fruit) {
        guard fruit.type == .pear, let pear = fruit.pear else {
            return nil
        }
        self.id = fruit.id
        self.pear = pear
    }
}

// 原有的Fruit、Apple、Pear定义保持不变
struct Fruit {
    enum FruitType {
        case apple
        case pear
        case unknown
    }

    let id: String
    let type: FruitType
    let apple: Apple?
    let pear: Pear?
}

struct Apple {
    let something: String 
}

struct Pear {
    let somethingElse: String
}

代码说明

  • 每个专属结构体(AppleFruit/PearFruit)都明确包含id和对应类型的数据属性,符合FruitProtocol要求。
  • 可失败初始化器通过guard语句同时校验水果类型和对应数据是否存在,任一条件不满足则返回nil。
  • 初始化成功时,直接给当前结构体的id和对应数据属性赋值,完成正确初始化。

内容的提问来源于stack exchange,提问作者André Gonçalves

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 07:40:25