最近我为iPhone做了一些开发,我注意到iPhone SDK中有很多有趣的设计模式,关于对象的可变性.
似乎典型的方法是定义一个不可变类NSFoo,然后从中派生出一个可变的后代NSMutableFoo.通常,NSFoo该类定义数据成员,getter和只读操作,以及派生NSMutableFoo者和变异操作的派生添加.
更熟悉C++,我不禁注意到这似乎与我在C++中编写相同代码时所做的完全相反.虽然你当然可以采用这种方法,但在我看来,更简洁的方法是创建单个Foo类,将getter和只读操作标记为const函数,并在同一个类中实现可变操作和setter.这样,你会最终有一个可变类,但类型Foo const*,Foo const&等等都是有效的不可变的相当的.
我想我的问题是,我对这种情况的看法是否有意义?我理解为什么Objective-C以不同的方式做事,但是我错过了C++中的两类方法有什么优势吗?还是我完全忽略了这一点?
这不是一个过于严肃的问题 - 更多的是出于我自己的好奇心而不是其他任何问题.
如何在闭包中调用方法?get_access_token方法可以基于以下内容设置新的访问令牌self.get_base_url():
fn fetch_access_token(_base_url: &String) -> String {
String::new()
}
fn get_env_url() -> String {
String::new()
}
pub struct App {
pub base_url: Option<String>,
pub access_token: Option<String>,
}
impl App {
pub fn new() -> App {
App {
base_url: None,
access_token: None,
}
}
pub fn get_base_url(&mut self) -> &String {
self.base_url.get_or_insert_with(|| get_env_url())
}
pub fn get_access_token(&mut self) -> &String {
self.access_token
.get_or_insert_with(|| fetch_access_token(self.get_base_url()))
}
}
fn main() {}
Run Code Online (Sandbox Code Playgroud)
错误:
锈2015
fn fetch_access_token(_base_url: &String) -> String …Run Code Online (Sandbox Code Playgroud) 我不明白这些情况:
content = {'a': {'v': 1}, 'b': {'v': 2}}
d1 = {'k1': {}}
d2 = {'k2': {}}
d1['k1'].update(content)
print(d1)
content['a']['v'] = 3
content['b']['v'] = 4
d2['k2'].update(content)
print(d2)
print(d1)
>>> {'k1': {'a': {'v': 1}, 'b': {'v': 2}}}
>>> {'k2': {'a': {'v': 3}, 'b': {'v': 4}}}
>>> {'k1': {'a': {'v': 3}, 'b': {'v': 4}}}
Run Code Online (Sandbox Code Playgroud)
在上述情况下,在更新可变内容之后改变d1的内容.
content = {'a': 1, 'b': 2}
d1 = {'k1': {}}
d2 = {'k2': {}}
d1['k1'].update(content)
print(d1)
content['a'] = 3
content['b'] = 4
d2['k2'].update(content) …Run Code Online (Sandbox Code Playgroud) 我想基于两个数组创建一个数组 - “ideaList”和“endorsements”全局声明。由于ideaList 和endorsements 用于程序的其他部分,我需要它们是不可变的,我认为 .map 和 .filter 会保持这种不变性。
function prepareIdeaArray(){
var preFilteredIdeas=ideaList
.filter(hasIdeaPassedControl)
.map(obj => {obj.count = endorsements
.filter(x=>x.ideaNumber===obj.ideaNumber)
.reduce((sum, x)=>sum+x.count,0);
obj.like = endorsements
.filter(x=>x.ideaNumber===obj.ideaNumber && x.who===activeUser)
.reduce((sum, x)=>sum+x.count,0)===0?false:true
obj.position = generatePosition(obj.status)
obj.description = obj.description.replace(/\n/g, '<br>')
return obj;});
preFilteredIdeas.sort(compareOn.bind(null,'count',false)).sort(compareOn.bind(null,'position',true))
return preFilteredIdeas;
}
Run Code Online (Sandbox Code Playgroud)
但是,当我在这个函数执行完console.logideaList的时候,注意到数组的对象都有“count”、“like”、“position”属性和值,证明这个数组已经发生了变异。
我尝试仅使用 .map,但结果相同。
你知道我如何防止ideaList发生变异吗?另外我想避免使用const,因为我首先全局声明ideaList,然后在另一个函数中为其分配一些数据。
允许访问者修改Receiver的状态或者应该是Command模式通常是否可以接受?
我对f#中变量的肤浅理解表明,将变量声明为"可变"并使用"ref"变量基本上都做同样的事情.它们是解决相同基础问题的不同方式 - 功能语言中有限且结构化的可变性允许,而不必求助于IO Monad.我的理解已经"抽象"了技术上的不同.
我很抱歉,如果这是一个多人,但他们似乎都相关.
我遇到了Java并发问题.是的,我看了几乎完全相同标题的问题,但他们似乎都在寻求微妙的不同之处.是的,我已经阅读了Java Concurrency in Practice.是的,我能看到为什么它是事实上的对话题参考.是的,我已经阅读了专门针对线程安全类中的发布字段的部分.是的,我仍然会问一个关于Java的并发问题,不管我知道有人会简单地指出我那本书.
这让我很难过 - 我知道你可以通过确保具有易变性和/或同步访问的正确读/写命令,以线程安全的方式轻松发布可变原语字段,并且64位原语需要具有原子访问权限由于其读/写操作缺乏原子性.我知道在需要在类的字段的特定"快照"上执行的代码块上使用锁.我完全了解原子包和AtomicLong <>等好东西.
但是我仍然对将非线程安全对象作为线程安全类中的字段发布感到困惑.
从我所看到的,一旦你在getter中返回对它的引用,你就可以在任何时候对调用者提供前所未有的对象内容访问权限.此外,如果你给一个setter,你允许他们将对象引用设置为一个对象,它们可以在他们使用setter的对象之外控制它们.
无论如何,我无法解决从非线程安全对象组成线程安全类而不使它们全部私有/受保护并在类中为所有非线程安全对象创建所有非线程安全对象的线程安全包装器方法让该类的用户可能想要使用.这听起来像是一个样板噩梦.
我的意思是,如果你将一个AtomicReference <>返回给getter中的对象,他们可以使用.get()来再次获得对它的非同步访问.
我考虑的另一种方法是让所有getter基于旧的获取非线程安全对象的新副本,这意味着修改将是无关紧要的,同样适用于setter.但是Java有一个无可救药的复杂系统来克隆对象(浅拷贝与深拷贝与特定拷贝等),这有点让我无法做到这一点.而且,这是如此低效,以至于它不会比使用像Clojure那样为不变性而设计的语言更快.事实上,考虑到这些语言允许多条不可变数据在幕后共享相同的数据,它可能会慢得多.
那么,如何以可行的方式编写已发布的非线程安全对象的线程安全类?
提前致谢.
在C#中,我想制作"智能"枚举,有点像Java中那样,其中有更多信息附加到枚举值而不仅仅是底层int.我发生了一个创建类(而不是枚举)的方案,如下面的简单示例所示:
public sealed class C
{
public static readonly C C1 = new C(0, 1);
public static readonly C C2 = new C(2, 3);
private readonly int x;
private readonly int y;
private C(int x, int y)
{
this.x = x;
this.y = y;
}
public int X
{
get
{
return this.x;
}
}
public int Y
{
get
{
return this.y;
}
}
}
Run Code Online (Sandbox Code Playgroud)
但是当我运行Visual Studio的"代码分析器"时,它会向我发出警告C2104,"不要声明只读可变引用类型".
我明白为什么你一般不想声明只读可变引用类型,但是...我的类不可变,是吗?
阅读警告的文档,似乎他们只是假设任何只读引用类型是可变的.例如,它表示如果类型确实是不可变的,那么请随意抑制此警告.事实上它给了我同样的警告,以下更简单的类:
public sealed class C
{
public static readonly C C1 …Run Code Online (Sandbox Code Playgroud) 我在模块中有一组需要访问某些共享初始化时间状态的函数.实际上,我想用静态可变矢量来模拟这个:
static mut defs: Vec<String> = vec![];
fn initialize() {
defs.push("One".to_string());
defs.push("Two".to_string());
}
Run Code Online (Sandbox Code Playgroud)
(示例:http://is.gd/TyNQVv,失败,"可变静态不允许有析构函数".)
我的问题类似于是否可以在Rust中使用全局变量?,但使用a Vec(即带有析构函数的类型),因此Option基于该问题的解决方案似乎不适用.也就是说,这失败的错误与我的第一次尝试相同:
static mut defs: Option<Vec<String>> = None;
fn initialize() {
let init_defs = vec![];
init_defs.push("One".to_string());
init_defs.push("Two".to_string());
defs = Some(init_defs);
}
Run Code Online (Sandbox Code Playgroud)
有没有办法访问在初始化时填充并在运行时可见的静态("全局")向量?
是否有其他模式我应该考虑支持这个用例?传递对状态向量的显式引用是可能的,但会混乱大量的函数签名,这些函数签名都需要访问此状态.
几天前,我发现了保罗·菲利普的主旨https://gist.github.com/paulp/9085746,这显示了很奇怪的行为.我没有找到任何解释这怎么可能
简化的代码段:
val buf = new ListBuffer[Int]()
buf ++= Seq(1,2,3)
val lst: List[Int] = buf.toIterable.toList
println(lst) //List(1,2,3)
buf ++= Seq(4,5,6)
println(lst) //List(1,2,3,4,5,6)
Run Code Online (Sandbox Code Playgroud)
它没有预期的工作 toIterable
val buf = new ListBuffer[Int]()
buf ++= Seq(1,2,3)
val lst: List[Int] = buf.toList
println(lst) //List(1,2,3)
buf ++= Seq(4,5,6)
println(lst) //List(1,2,3)
Run Code Online (Sandbox Code Playgroud)
那里发生了什么?
mutability ×10
closures ×2
immutability ×2
rust ×2
arrays ×1
c# ×1
c++ ×1
composition ×1
concurrency ×1
dictionary ×1
f# ×1
java ×1
javascript ×1
list ×1
nested ×1
objective-c ×1
python ×1
scala ×1
static ×1