【问题标题】:Cannot assign to immutable expression of type ... but with protocols无法分配给类型的不可变表达式......但使用协议
【发布时间】:2018-03-19 23:00:01
【问题描述】:

我知道有很多这样的问题。但是,这是我的代码 sn-p:

protocol AProt { var a:Int { get set } }
protocol BProt { var b:Int { get set } }
protocol CProt { var c:Int { get set } }
class A:AProt, CProt { var a = 1;  var c = 3 }
class B:BProt, CProt { var b = 2; var c = 30 }

var a = A()
var b = B()
var c = a as CProt // works
c.c = 123
a = c as! A
print (a.c)
(a as CProt).c = 999 // throws error
print (a.c)

查看this answer 它告诉(...as...) 使表达式不可变。但是……

虽然(a as CProt).c = 999 失败并显示上述错误消息,但使用var c = a as CProt 的解决方法可以工作。我认为这是一个简单的编译器错误,但我想知道这里是否可以做一些事情(比如添加一个秘密关键字)。

【问题讨论】:

  • 如果您可以简单地分配a.c = 999as CProt 演员表的原因是什么?
  • @MartinR 好吧,这是一个缩小的例子,整个上下文都会解决这个问题。或许我得重新思考,再次从后门进入整件事。

标签: swift protocols


【解决方案1】:

这不是编译器错误。 CProt 可以是值类型。考虑这段代码:

protocol CProt { var c:Int { get set } }
struct A: CProt { var a = 1;  var c = 3 } // Note this is a struct
var a = A()  // It's mutable
let c = a as CProt  // But this one isn't
c.c = 999  // So no surprise this fails

您希望这会起作用吗?它不应该,因为c 是一个不可变结构。这与您在(a as CProt).c = 999 中写的内容相同。

问题是你期望CProt 是一个引用类型。如果您需要,请说出来:

protocol CProt:class { var c:Int { get set } } // Note the addition of :class
class A: CProt { var a = 1;  var c = 3 }
let a = A()
(a as CProt).c = 999 // Success

【讨论】:

  • 嗨@Rob,这是我的第一个想法,但请考虑以下几点:如果 a 是一个结构,那么 var c = a as CProt 创建一个 copy。所以在(a as CProt) 的情况下,这可以 也创建一个副本,所以将 anthing 分配给该副本没有问题。我知道这不是他们迅速实施的方式,为什么他们不这样做?还是这里遗漏了什么?
  • 如果(a as CProt) 创建了一个可变副本,它就没有用了,因为它会立即被销毁。那将是非常混乱和容易出错的。创建一个不可变的副本是可以的(确实如此),但是如果您更改了它并且您的更改立即丢失了,这与不更改它是一样的。
  • 当我说“(确实如此)”时,我的意思是“它相当于创建一个不可变的副本”。它可能会或可能不会实际复制任何数据。但您必须将其视为有效地创造新价值。
  • 啊! :class 是秘诀。谢谢!
  • 对不起,我把lede埋在那里了。进行了编辑以使其更清晰。
猜你喜欢
  • 2016-08-02
  • 1970-01-01
  • 2015-11-12
  • 2017-05-16
  • 2017-04-14
  • 1970-01-01
  • 2014-12-03
  • 1970-01-01
  • 2019-10-30
相关资源
最近更新 更多