使用Swift结构体构造函数作为函数

3

假设有这样一个定义:struct S

struct S {
    let a : String 
    let b : Int 
    let c : Bool 
}

还有一个名为sConstructorFun的函数

func sConstructorFun(#a:String, #b:Int, #c:Bool) -> S { 
    return S(a:a, b:b, c:c) 
}

我可以使用sConstructorFun(a:"", b:1, c:false)S(a:"", b:1, c:false)这两种方式获取下面S的值(如REPL将其输出)

S = {
  a = ""
  b = 1
  c = false
}

所以SsConstructorFun具有完全相同的接口,并且返回相同的结果,这并不奇怪。

然而,一个定义如下的sFactory函数

func sFactory(f:(String, Int, Bool) -> S) -> S {
    return f("foo", 42, false) 
}

该方法只能与sConstructorFun一起使用,而不能直接使用S

REPL> sFactory(sConstructorFun) 
$R2: S = {
  a = "foo"
  b = 42
  c = false
}

并且

REPL> sFactory(S) 
repl.swift:18:1: error: cannot invoke 'sFactory' with no arguments
sFactory(S)
^
repl.swift:18:9: note: expected an argument list of type '((String, Int, Bool) -> S)'
 sFactory(S)
         ^

有没有办法将struct的默认构造函数(在这个例子中是S)作为一个函数使用(而不需要定义新的函数/闭包来完成)?

我不清楚你在 S = { a = "", b = 1, c = false } 中的意思。S 是结构体,然后你将 S 用作左值。这个语法似乎不是有效的 Swift 结构。 - Matteo Piombo
@MatteoPiombo 这就是REPL输出结构体的方式: 18> S(a:"foo", b:1, c:false) $R3: S = { a = "foo" b = 1 c = false } - Johannes Weiss
对不起!我取消了一个建议的编辑,建议将func sConstructorFun(#a:String, #b:Int, #c:Bool) -> S更改为func sConstructorFun(a a:String, b b:Int, c c:Bool) -> S,因为我认为这意味着不同的东西。对此我深感抱歉,现在我会重新应用该编辑。 - Johannes Weiss
发布为 rdar://19849369 || http://openradar.appspot.com/19849369 - Johannes Weiss
2个回答

2

您只需要将默认构造函数放在闭包中并将其传递给 sFactory 函数即可。尝试以下代码:

let f = { S(a: $0, b: $1, c: $2) }

func sFactory(f:(String, Int, Bool) -> S) -> S {
    return f("foo", 42, false) 
}

let s = sFactory(f)

println("s = (a: \(s.a), b: \(s.b), c: \(s.c))") // S = (a: foo, b: 42, c: false)

这是定义一个新函数 f,它与我的sConstructorFun相同,只是没有标记参数。虽然这样可以节省一些打字时间。澄清了问题。 - Johannes Weiss
Joe Groff,一位Swift开发者刚刚通过Twitter确认,目前还不可能实现,最简单的方式实际上是定义一个包装函数来调用 :-(。因此,我会接受你的答案。 - Johannes Weiss
我认为问题在于,如果你只使用字母 S,Swift 就不知道你想对它做什么。你可能正在尝试将类型作为参数传递,或者进行任何其他与此相关的操作。不过我很好奇,这种情况在其他编程语言中是否常见?有没有一些语言可以将类型名称传递给函数,并推断出你正在尝试调用构造函数呢?那会很酷...... - Aaron Rasmussen

0

我不太清楚你的意图,但也许你正在寻找以下类似的构造函数:

extension S {
    init (f: (a: String, b: Int, c: Bool) -> S) {
        self = f(a: "foo", b: 1, c: true)
    }

    init(f: () -> S) {
        self = f()
    }
}

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