将默认参数值发送给函数?

时间:2016-10-29 00:49:08

标签: swift default-arguments

TL; DR

如果我有func show(message: String = "Hello"),如何在不省略参数名称的情况下向默认参数发送? (例如show(message: default)

注意:show()不是我想要的!请参阅下面的详细信息。

想象一下,我们定义了以下功能:

func makeCreature(color: UIColor, eyeCount: Int = 2, noseCount: Int = 1) -> Creature {
  // ...
}

然后我们还定义了另一种方法makeCreatures

func makeCreatures(count: Int, color: UIColor) {
  for 1...count {
    makeCreature(color: color)
  }
}

但是,现在我们想要轻松自定义makeCreatures的eyeCount和noseCount。一种方法是重新定义参数及其默认值:

解决方案#1

func makeCreatures(count: Int, color: UIColor, eyeCount: Int = 2, noseCount: Int = 1) {
  for 1...count {
    makeCreature(color: color, eyeCount: eyeCount, noseCount: noseCount)
  }
}

问题在于,如果眼睛的默认数量发生变化,我需要记住在两个地方更新它:makeCreaturemakeCreatures

我希望做的是将方法定义为:

func makeCreatures(count: Int, color: UIColor, eyeCount: Int? = nil, noseCount: Int? = nil)

但是,现在这意味着我必须创建4个不同的if分支:

解决方案#2

func makeCreatures(count: Int, color: UIColor, eyeCount: Int? = nil, noseCount: Int? = nil) {
  for 1...count {
    if let eyeCount = eyeCount, let noseCount = noseCount {
      makeCreature(color: color, eyeCount: eyeCount, noseCount: noseCount) 
    } else if let eyeCount = eyeCount {
      makeCreature(color: color, eyeCount: eyeCount)
    } else if let noseCount = noseCount {
      makeCreature(color: color, noseCount: noseCount)
    } else {
      makeCreature(color: color)
    }
  }
}

必须创建4个不同的分支有点难看并且难以理解。是否有更好的方法可以让我在#2的干燥度下获得解决方案#1的简洁性?类似的东西:

理想解决方案?

func makeCreatures(count: Int, color: UIColor, eyeCount: Int? = nil, noseCount: Int? = nil) {
  for 1...count {
    makeCreature(color: color, 
      eyeCount: eyeCount ?? default, 
      noseCount: noseCount ?? default)
  }
}

其中default表示使用makeCreature中定义的默认参数值(2 eyeCount1 noseCount)。

如果没有,那么可以帮助我实现这一目标的其他解决方案是什么?

2 个答案:

答案 0 :(得分:0)

这并不是您正在寻找的,但您可以使用构建器模式:

struct Creature {
    let color: UIColor
    let eyeCount: Int
    let noseCount: Int
}

struct CreatureBuilder {
    var color: UIColor?
    var eyeCount: Int = 2 //store defaults here
    var noseCount: Int = 1

    func build() -> Creature {
        guard let color = color else { fatalError("Creatures need a color!") }

        return Creature(color: color, eyeCount: eyeCount, noseCount: noseCount)
    }
}

func makeCreatures(count: Int, color: UIColor, eyeCount: Int? = nil, noseCount: Int? = nil) {
    var builder = CreatureBuilder()
    builder.color = color;
    if let eyeCount = eyeCount { builder.eyeCount = eyeCount } //override defaults only for non-nil params
    if let noseCount = noseCount { builder.noseCount = noseCount }

    for _ in 1...count {
        let creature = builder.build() //TODO: do something with the creature.
    }
}

答案 1 :(得分:0)

为了完整起见,还有另一种类似于Alexander's的解决方案。

您可以创建一个结构来保持生物的属性:

struct Attributes {
  let color: UIColor
  let eyeCount: Int = 2
  let noseCount: Int = 1
}

然后重新定义要接受属性的函数:

func makeCreature(attributes: Attributes) -> Creature {
  // ...
}

func makeCreatures(count: Int, attributes: Attributes) {
  for 1...count {
    makeCreature(color: color, attributes: attributes)
  }
}

允许您对两个函数使用默认值:

// uses 2 eyes (default), and 2 noses
makeCreature(attributes: Attributes(color: .purple, noseCount: 2))

// use 10 eyes, and 1 nose (default)
makeCreatures(count: 3, attributes: Attributes(color: .blue, eyeCount: 10))