如何初始化一个空结构体?

5

我不知道如何初始化下面的结构体?基本上,我想创建一个表示下面结构体的空变量,但是值应该是可选/nil的,但我不知道如何做。

// MARK: - Main
struct Main: Codable {
    let meta: Meta
    let objects: [Object]
}

// MARK: - Meta
struct Meta: Codable {
    let status: String
    let count, offset, totalcount: Int
}

// MARK: - Object
struct Object: Codable {
    let id:Int
    let url: String
    let displayname: String
    let inventory: [Inventory]
    let media: [Media]
}


// MARK: - Inventory
struct Inventory: Codable {
   let id, warehouseid, instock, threshold: Int
    let reserved: Int
    let coordinates, note: String
    let prodno: Int
    let lastinventory: String
    let soldout, onpurchaseorders, generation: Int
    let created, changed: String
}

// MARK: - Media
struct Media: Codable {
    let id, prodno: Int
    let webpath: String
    let slot: Int
    let type, extdata: String
    let ctime, xsize, ysize, mediasetid: Int
    let alt, title: String
    let generation: Int
    let created, changed: String
}

以下代码会出现 "no exact matches in call to initializer" 的错误消息,如果我更改代码还会出现其他一系列的错误。

var sökresultat3 = Main3()

基本上我想创建一个空变量,代表下面的结构体,但你可能并不需要这样做。你到底想要实现什么? - Alexander
@Alexander 我同意过度使用可选项可能不好,但你反对一个空的“默认”Main吗?那似乎是非常自然的事情。你在这里担心什么? - Rob Napier
我不知道Main是什么,所以很难说。但“使所有字段可为空”的味道引起了我的注意。 - Alexander
3个回答

5
如果您希望属性成为可选项,那么您必须以这种方式声明它们。Int表示您需要一个整数。如果您想要一个可选的整数,则声明为Int?
话虽如此,我认为在创建太多可选项,特别是可选数组和字符串时,应该考虑得很周到。在您的系统中,“没有库存”(nil)与“空库存列表”([])之间是否有区别?还是“没有名称”(nil)和“空名称”("")?如果这些都相同,则通常情况下,您会更喜欢只有默认值,而不是可选值。可选值增加了很多您可能不需要的复杂性。
作为默认值的示例,使用var将使这个过程变得简单,并给您所希望的初始化程序:
struct Main: Codable {
    var meta = Meta()
    var objects: [Object] = []
}

// MARK: - Meta
struct Meta: Codable {
    var status = ""
    var count = 0
    var offset = 0
    var totalcount = 0
}

如果您将它们定义为可选项,那么var会再次创建您需要的初始化程序。
struct Main: Codable {
    var meta: Meta?
    var objects: [Object]?
}

通常情况下,对于没有逻辑的简单数据结构应该声明它们的属性为var。有一些例外情况,例如Identifiable结构体,它们应该将它们的id声明为let,因为它们的id具有一些特殊含义。但通常来说,过度使用let会使结构体难以使用而没有任何好处。(值类型永远不会共享,所以变异不是问题。)
如果您仍想使用let,则需要手动定义自己的init

嗨,罗布!感谢你的回答。我已经尝试将所有内容声明为“?”,但是当我尝试使用var sökresultat3 = Main3()进行初始化时仍然会出现错误,它说:“在调用中缺少参数'from',请插入'from:<#Decoder#>。 - Axxi
Codable不会影响到这个init,如果你使用var,你就不需要编写自己的init。问题是"let带值"被视为常量,而不是默认值。 - Rob Napier
@RobNapier,Optionals在这个上下文中增加了什么复杂性?我认为默认值会增加更多的复杂性,因为我需要询问isStringEmpty?或isNumberZero?等等...然后在代码中使用三元表达式为每种情况选择替代值,而不是仅对所有类型使用??表达式。 - vigdora

1
如果你的结构体中所有属性都是可选的,并且将它们全部定义为var,Swift会创建一个初始化器,将所有属性默认设置为nil。就好像你定义了以下结构体一样:
struct AStruct {
    var a: Int?
    var string: String?
    
    //You don't have to define this initializer if all your properties are var Optionals
    init(a: Int? = nil, string: String? = nil) {
        self.a = a
        self.string = string
    }
}

您可以像这样调用该初始化器:

var aStruct = AStruct()

如Alexander所指出的那样,仅仅因为你可以这样做,并不意味着你应该这样做。这似乎不是一个好的实践方法。

Swift会自动为您编写这个初始值设定项,给定这个结构体。不需要手动编写。 - Rob Napier
我认为这是一个巨大的反模式,我不建议这样做。来自使用默认初始化为0、false、null等的外语的开发人员可能会尝试使用类似的东西,但这几乎永远不是他们实际需要的。 - Alexander

0

main 改为以下内容

struct Main: Codable {
var meta: Meta?
var objects: [Object]?
}

嗨,Luca!感谢你的回答。我已经尝试过这个方法,但是当我尝试使用var sökresultat3 = Main3()进行初始化时,它仍然会出现错误,提示“在调用中缺少参数'from',请插入'from:<#Decoder#>。” - Axxi
刚刚编辑了问题,请告诉我是否有效。 - Luca Sfragara

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接